当你可以使用动态LINQ时,规范模式是否已过时?

7

Wikipedia 表示,规范模式是通过使用布尔逻辑将业务逻辑链接在一起以重新组合业务逻辑的地方。就从列表或集合中选择过滤对象而言,似乎动态LINQ允许我完成相同的事情。我有什么遗漏吗?还有其他应考虑的规范模式的好处吗?


编辑:

我找到了一些讨论如何将LINQ和规约模式结合起来的帖子:

Linq规约项目

通过Linq实现规约模式,作者是Nicloas Blumhardt(Autofac的家伙)

有人尝试过这样做吗?是否变得难以维护?


我现在几乎正面临着这种情况,所以这个问题对我来说非常有兴趣。 - Michael Cook
4个回答

6
我是一名C#开发人员,喜欢使用规范模式,因为它更贴近我的业务领域。此外,这种模式不会有任何意外,如果存在规范类,则应该有效。使用Linq时,底层提供程序可能未实现某些功能,直到运行时才会发现。
但毫无疑问,规范模式比LINQ更接近业务,它是一个小型DSL。对我而言,LINQ是用于集合查询的DSL,而不是用于业务领域的DSL。

3

LINQ:

var oldMans = Persons.Where(x => x.Sex == SexEnum.Masculine && x.Age > 60).ToList();

规格:

var oldMans = Persons.Where(x => IsOldManSpecification(x)).ToList();
  • 业务逻辑被封装在规范中(其中规范的名称表明了其含义)。
  • DRY原则:在代码中不要重复使用Linq,只需使用规范。

当我认为规则对代码来说非常重要且无法自然地属于实体时,我喜欢使用规范。

例如:

public class Customer
{
    //...

    public bool IsAbleToReceiveCredit(decimal creditValue)
    {
        var secureAge = this.Age > 18 && this.Age < 60;
        var personalAssetsGreaterThanCreditValue = this.PersonalAssets.Sum(x => x.Value) > creditValue;

        return secureAge && personalAssetsGreaterThanCreditValue;
    }
}

客户是否有能力接受信用贷款是由客户决定的责任吗?银行会要求客户能否接受贷款吗?

很可能不是。

因此,您可以使用规范将该逻辑从Customer(它从未属于过)中删除。您可以创建类似于IsAbleToReceiveCreditSpecification这样的东西,并将所有逻辑放在那里。我们还可以进一步组合规格,例如:您可以创建一个SecureAgeSpecification 和一个 AssetsGreaterThanSpecification 并将它们用于组成IsAbleToReceiveCreditSpecification

因此,我不认为LINQ替代了规范。实际上,它改善了模式。有一些规范的实现内部使用具有IQueriable<T>的LINQ,在存储库/数据访问级别上使用规范查询ORM查询。


2
动态LINQ使用字符串表达式来允许动态查询构建。因此,我们实际上会失去类型安全性。而使用装饰器模式等包装器模式的相关实现,如规范模式,可以使我们在代码中保持类型安全性。我探索了在查询包装器中使用装饰器模式以便重用和动态构建查询。您可以在code project上找到这篇文章: Linq Query Wrappers 或者您可以查看我的博客

1

我不太了解LINQ,但似乎一般来说,声明式查询系统与规范模式有关。特别是在面向对象的环境中通过组合对象来实现声明式查询系统。如果我没记错的话,这就像LINQ所做的那样,提供了一层语法糖。

无论LINQ是否完全淘汰了该模式,我无法确定。也许有一些边角案例无法用LINQ表达?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接