(183)Change_Reference_to_Value
將引用物件改為實質物件
如果Reference Object ,很小且不可變,也不易管理,就可以使用此技巧
如同(179)Change_Value_to_Reference有Value Object to Reference Object
就有 Reference Object to Value Object,這兩個之間本來就很難決定。
如果Reference Object 用得多,可能會造成前面的(179)Change_Value_to_Reference說明一樣,用得太多會亂,其實也未必是一件好事,此技巧也可以解決這類的問題
Value Object 有一個重要的特性,就是他們不可變(Immutable),無論何時你呼叫這個物件的查詢函式,應該都得到一樣的結果
如果Value Object 是可變的,你就必須確保你對某一個物件的修改會自動更新他【代表相同的事物】,這太痛苦了,與其如此不如就把它改成Reference Object
可變(mutable) VS 不可變(immutable)
不可變(immutable): 即物件一旦被建立初始化後,它們的值就不能被改變,之後的每次改變都會產生一個新物件。
例如:string 不可變
var str="mushroomsir";
str.Substring(0, 6)
// c#中的string是不可變的,Substring(0, 6)返回的是一個新字串值,而原字串在共享域中是不變的。另外一個StringBuilder是可變的,這也是推薦使用StringBuilder的原因。
var age=18;
age=2;
// 此時會記憶體中新值2賦值給age變數,而不能改變18這個記憶體裡的值
物件的value object
// 可變的範例
class Contact
{
public string Name { get; set; }
public string Address { get; set; }
public Contact(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
}
// client code
var mutable = new Contact("二毛", "清華");
mutable.Name = "大毛";
mutable.Address = "北大";
// new 了之後又可以修改他的值
在多執行緒就會出現,資料撕裂(A、B執行緒讀到的資料不一樣)
變成reference object 方法
public class Contact2
{
public string Name { get; private set; }
public string Address { get; private set; }
private Contact2(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
public static Contact2 CreateContact(string name, string address)
{
return new Contact2(name, address);
}
}
只能通過建構式才可以修改裡面的值,所以每次使用該物件都必須重新New這個物件
可以完整資料完整性、保證安全性,也不會被執行緒修改到
範例
// 一個reference object
class Currency{
private string _code;
public string getCode(){
return _code;
}
private Currency(string code){
_code = code;
}
}
// client code
Currency usd = Currency.get("USD");
// 建構式是Private無法建立
new Currency("USD").equals(new CUrrency("USD")) // return false
要把reference object 變成 value object 灌見動作是:檢查他是否為immutable(不可變)
如果不是,就不可能使用這方法重構,因為Mutable(可變的) value object 會造成令人苦惱的別名現象(aliasing)
// 猜猜下面答案會是 True or Flase ?
bool sample(){
return new Currency("USD").Equals(new Currency("USD"));
}
void Main()
{
bool sample(){
return new Currency("USD").Equals(new Currency("USD"));
}
Console.WriteLine(sample());
}
class Currency {
public string Name {get; private set;}
private string othervalue = ""; // 其他驗證的欄位
public Currency(string name){
Name = name;
}
// 調整二 把檢驗方式修正
public override bool Equals(object obj){
return Name.Equals(((Currency)obj).Name);
}
// 調整二 所有要驗證的欄位都要加上 ^
public override int GetHashCode(){
return Name.GetHashCode() ^ othervalue.GetHashCode();
}
}
後繼
平常開發多半都使用的是可變 + Value Object,而使用Reference 的機會並不多
在加上這重構的手法,真的比較少見,感覺用到的機率也不算太大
但這是一個不錯的學習範例,可以有印象即可