Posts Tagged ‘refactoring’

利用Func<T, TResult>进行重构

August 8, 2007 Tags: , ,

你开发中的令人心动的Web2网站的底层数据库中有一张用户表,为了与时俱进,你决定用.NET 3.5呀、LINQ什么的来开发。

在实现自己的MembershipProvider的时候,你发现需要实现依据电子邮件或用户名来查找用户的功能,所以你啪嗒啪嗒地敲出了以下代码:

public User FindByEmail(string email)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(u => u.Email == email);
return user;
}

使用Paste & Copy大法,另一个方法呼之即来:

public User FindById(int id)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(u => u.UserId == id);
return user;
}

正打算沾沾自喜时,作为一名正在学习重构的用功的程序员,你发现这两段代码有臭臭的重复的味道。将来网站做大了,可能还要实现FindByAge、FindByMSN、FindByQQ等等方法,你可不想每次拷来拷去把相同的逻辑复制多份,毕竟这年头,代码的价值与LOC是不成正比的。

所以,你打算实现一个通用的Find方法:

private User Find(what?)
{
User = ...;
return user;
}

你注意到要完成这个伟大的算法,需要告诉它你是要查找一个User类型的对象,并且需要把查找的逻辑给传递进去。马上打开.NET类库寻找,很快就找到了这个东东:

public delegate TResult Func(T arg);

嗯,这正是我需要的。你嘀咕着,同时把这个Find方法改为:

private User Find(Funcbool> predicate)
{
CoolWeb2DataContext db = new CoolWeb2DataContext();
var user = db.Users.SingleOrDefault(predicate);
//eh, 也许该作些判空什么的事,还是留到用户数上百万再说吧
return user;
}

这下,原来的两个方法都清爽了:

public User FindByEmail(string email)
{
    return Find(u => u.Email == email);
}
public User FindById(int id)
{
    return Find(u => u.UserId == id);
}

离这个要轰动全球的网站的发布,又进了一大步,再完成99.7%的代码,就可以Beta了。把代码签入,你开心地吃晚饭去了。