若是你有一個引用對象,很小且不可改變,並且不易管理,你就須要考慮將他改成一個值對象。在Change Value to Reference咱們說過,要在引用對象和值對象之間作選擇,有時候並不容易,有了重構,作出選擇以後,你還有一條回頭路。html
若是你發現引用對象開始變得難以使用,你就考慮是否應該把它改成值對象。引用對象必須被某種方式控制,你老是必須向其控制者請求適當的引用對象。若是你讓你形成在你係統內存之間變得錯綜複雜。或者在分佈系統和併發系統中,不可變值特別有用(你須要考慮可變對象引用對象他們的同步關係)。併發
值對象有一個很是重要的特性----它應該是不可變的。不管什麼時候,只要你調用同一個對象的同一個查詢函數,它返回的結果應該是同樣的。若是你能夠保證這一點,你能夠放心的讓多個對象表示同一個事物。若是值對象是可變的,你就必須確保某一個對象的修改會自動更新到其餘表明相同事物的對象中去。那此時你應該使用引用對象了。函數
什麼是不可變?不可變意味着若是你以Money來表示金錢,那麼Money一般是一個不可變的值。這並非意味着你的金錢不能改變。而是意味着若是你改變薪資,你必須用另外一個對象來替換如今的Money對象,而不是在如今的Money對象上作修改。注意這裏面的說法,這種改變就相似與咱們原子級別的內置變量,舉個例子測試
int age = 13; age = 14; // right age = int(13).setIntValue(14); // false
對於內置類型int來講就是一個最簡單的值類型,咱們的年齡age在從13改變到14的時候,正是替換了如今的對象,產生了一個int(14)而不是直接在13對象上作修改。對於Money來講this
Money mon = Money(3); mon = Money(4); // right mon = mon.setValue(4); // false
咱們的mon也是作了對象的替換,而不會去採用setValue的形式去作修改。始終記住:值對象自己是不可修改的。spa
例子:code
class Currency { private: Currency(const QString &code) : m_code(code) { }
public:
QString code() const { return m_code; } private: QString m_code; };
這個貨幣類目前是一個引用對象,咱們如今想獲得他,必須經過這種方法htm
Currency *usd = Currency::get("USD");
Currency內部維護一個Hash表用來保存預先建立好的Currency實例,咱們也不能直接經過構造函數來構造他們,由於此時的構造函數是私有的。要把一個引用對象變成值對象,關鍵動做是觀察它是否可變,若是他可變,那就別用這次重構,由於後期的別名同步問題還很煩人。在這裏Currency是不可變的,咱們爲它重載==對象
bool operator==(const Currency &value) { if (this == &value) { return true; } else { return this->m_code == value.code(); } }
完成這個以後咱們進行編譯,測試。如今咱們想建立多少個Currency都沒問題,咱們還能夠把他的構造函數聲明爲public,咱們能夠直接用構造函數來獲取Currency實例,從而去掉工廠函數和控制實例建立的行爲。blog