Value Object, value type, Property , struct , Null object, Immutable object
寫程式時,常常會用到屬性來對外開放存取
現況
public string DisplayName
{
get
{
return this._version;
}
set
{
this._version = value;
}
}
如果今天需要在 set value 時作驗證與判斷
public string DisplayName
{
get
{
return this._version;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value")
}
this._version = value;
}
}
再進一步,在特殊情況,給定一個default value
public string DisplayName
{
get
{
return this._version;
}
set
{
var temp = value;
if (temp == null)
{
temp = String.Empty;
}
this._version = temp ;
}
}
上述的程式碼雖然帶來便利,但是會讓使用者帶來混亂,假設使用者set null value,所以他會預期get value時,回傳null
結果得到一個String.Empty,Amazing!
該怎麼辦?
Encapsulation是王道。
讓我們試著把驗證規則、預設值等等封裝成Immutable Object。
public class OrganizationVersion
{
private readonly string _version;
public OrganizationVersion(string pVersion)
{
// 驗證規則 預設值 轉換格式等等
if (pVersion == null)
{
throw new ArgumentNullException("pVersion");
}
this._version = pVersion;
}
public string DisplayName
{
get
{
return this._version;
}
}
}
public class Test
{
public Version DisplayName
{
get;
set;
}
}
但是這樣依然需要判斷null的情況
改成使用struct實作,再加上一點輔助功能
/// <summary>
/// Version
/// </summary>
internal struct Version
{
/// <summary>
/// version display name
/// </summary>
private string _version;
/// <summary>
/// 是否已設值
/// </summary>
private readonly bool _flag;
/// <summary>
/// ctor
/// </summary>
/// <param name="pVersion">version</param>
public Version(string pVersion)
{
//驗證規則
this._version = pVersion;
this._flag = true;
}
/// <summary>
/// vesrion property
/// </summary>
public string DisplayName
{
get
{
if (!this._flag)
{
this._version = "DefaultValue";
}
return this._version;
}
}
/// <summary>
/// implicit 轉換 Versionto string
/// </summary>
/// <param name="pVersion">version</param>
/// <returns>displayname</returns>
public static implicit operator string(Version pVersion)
{
return pVersion.DisplayName;
}
/// <summary>
/// explicit 轉換 string to Version
/// </summary>
/// <param name="pDisplayName">version displayname</param>
/// <returns>Version</returns>
public static explicit operator Version(string pDisplayName)
{
return new Version(pDisplayName);
}
/// <summary>
/// override tostring
/// </summary>
/// <returns>displayname</returns>
public override string ToString()
{
return this._version;
}
/// <summary>
/// override GetHashCode
/// </summary>
/// <returns>int</returns>
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
}
結果
var test = new Test();
//預設值
string displayName = test.DisplayName.DisplayName;
test.DisplayName = new Version("TestDisplayName");
//displayName = "TestDisplayName"
displayName = test.DisplayName.DisplayName;
//implicit, displayName = "TestDisplayName"
displayName = test.DisplayName;
//displayName = "TestDisplayName"
displayName = test.DisplayName.ToString();
好處
減少重複程式碼
封裝驗證規則與資料
提供預設值
避免null判斷
其他
http://blog.ploeh.dk/2011/05/26/CodeSmellAutomaticProperty.aspx
http://grabbagoft.blogspot.com/2007/12/dealing-with-primitive-obsession.html