利用Func进行重构

你开发中的令人心动的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, TResult>(T arg);

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

private User Find(Func<Models.User, bool> 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了。把代码签入,你开心地吃晚饭去了。