最近整理了一下公司規范,其中“函數的參數個數不宜超過4個”這一條在推廣的時候有些爭議,在能完成任務的情況下參數越少肯定越好,這本身沒什麼可爭議的,但這樣做可能會在編程時帶來困難,爭議點在是否值得這樣做。我覺得為了讓使用函數者更簡單這樣做還是值得,至於編程時的困難往往是因為我們不熟悉一些減少參數的方法,這裡總結幾條供大家參考:
1、使用結構來封裝參數
例子:添加用戶
原函數體:AddUser(string userName,string passWord,string address,string phone,int age)
重構:添加一個User類:
class User
{
public string UserName { get; set; }
public string PassWord { get; set; }
public string Address { get; set; }
public string Phone { get; set; }
public int Age { get; set; }
}
將AddUser改為:AddUser(User user)
存在的問題:如果添加的這個類沒有其他地方用,常常會覺得這樣做並不值得,這時我們可以考慮使用匿名類封裝參數的方法。
2、使用屬性來替換參數
如果將1中的AddUser方法置於User類中,那麼AddUser方法中的user參數都可以省掉了,有的時候可能為了減少某些方法的參數個數而添加某些屬性。面向對象設計中,對象應該自己負責自己,而且應該清楚定義責任。某個方法參數太多的原因可能是這個方法寫在了他不該存在的地方,GRASP原則中講的“信息專家”模式很多情況下可以減少參數的個數。
例子:帳戶轉賬
原函數:Transfer(Account from,Account to,decimal money)
重構:
代碼
public class TransferPRocess
{
private Account From;
private Account To;
public TransferProcess(Account from, Account to)
{
this.From = from;
this.To = to;
}
public void Transfer(decimal money)
{
if (money<From.Money)
{
From.Money = From.Money - money;
To.Money = To.Money + money;
//更新數據庫
}
else
{
throw new Exception("超出余額");
}
}
}
注:信息專家模式是面向對象設計的最基本原則,我們設計對象(類)的時候,如果某個類擁有完成某個職責所需要的所有信息,那麼這個職責就應該分配給這個類來實現。這時,這個類就是相對於這個職責的信息專家。
3、使用私有函數
調用某個函數時往往並不需要很多的交互參數,但我們提供參數時則需要提供所有的情況,這時我們可以把函數分類,將最復雜的函數封裝成私有的,而暴露出來的簡單函數調用這些復雜函數完成功能。我們來看看mvc中的TextBox方法的實現方式:
代碼
public static string TextBox(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> HtmlAttributes) {
return InputHelper(htmlHelper, InputType.Text, name, value, (value == null) /* useVIEwData */, false /* isChecked */, true /* setId */, true /* isExplicitValue */, HtmlAttributes);
}
private static string InputHelper(this HtmlHelper htmlHelper, InputType inputType, string name, object value, bool useVIEwData, bool isChecked, bool setId, bool isExplicitValue, IDictionary<string, object> HtmlAttributes) {
if (String.IsNullOrEmpty(name)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
}
TagBuilder tagBuilder = new TagBuilder("input");
... ...
但有時我們為了給調用者最大的靈活性,可能也會把最復雜的那個函數重載暴露出來。
4、params 關鍵字
指定在參數數目可變處,采用參數的方法參數。
用法:
代碼
static void Main(string[] args)
{
UseParams(1, 2, 3);
}
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.WriteLine(list[i]);
}
Console.WriteLine();
}
這種方法實際上並沒有減少參數的個數,只是簡化了函數體。
5、使用匿名類封裝參數
准備知識:我們先來看看RouteValueDictionary
代碼
static void Main(string[] args)
{
RouteValueDictionary r = new RouteValueDictionary(new { id=1,name="lfm"});
foreach (var item in r)
{
Console.WriteLine("{0}:{1}", item.Key, item.Value);
}
//Console.WriteLine();
}
結果:
id:1
name:lfm
RouteValueDictionary可以將實例的屬性名及屬性值存入到字典中。
mvc中很多地方使用這種方式傳遞參數。
比如: <%= Html.ActionLink("Details", "Details", new { id=item.id })%>
ActionLink方法體中就是使用RouteValueDictionary將匿名對象進行了分解,然後將其拼裝到鏈接上。