7

我正在做一些研发工作,因此正在探索设计模式。我最近一直在阅读规范模式,并提到了这篇很棒的文章。

我对代码的简洁性和简洁性很感兴趣,但我开始对使用其他技术实现相同的简洁性进行一些比较。

考虑以下服务层的接口契约:

public interface IFooDataService
{
   ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification);
   ICollection<Foo> GetFooByPredicate(Func<Foo,bool> predicate);
   ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs);
}

所以,一些初始点:

  • 所有三个都返回 Foo 对象的集合
  • 三者都接受一个论点
  • 规范方法限制对特定要求的访问
  • 谓词方法基本没有限制
  • 搜索 args 方法限制对特定要求的访问

现在,进入实现:

public ICollection<Foo> GetFoosBySpecification(Specification<Foo> specification)
{
    return fooDataRepository
            .Find()
            .Where(f => specification.IsSatisfiedBy(f))
            .ToList();
}

public ICollection<Foo> GetFooByPredicate(Func<Foo, bool> predicate)
{
    return fooDataRepository
            .Find()
            .Where(predicate)
            .ToList();
}

public ICollection<Foo> GetFooBySearchArgs(FooSearchArgs searchArgs)
{
    return fooDataRepository
            .Find()
            .WhereMeetsSearchCriteria(searchArgs)
            .ToList();
}

实施要点:

  • 这三个在实现上都非常简单(一行链式代码)
  • 规范和搜索参数过滤在外部实现。
  • 搜索 args 方法只是使用 IEnumerable 扩展方法来检查 args

那么,话虽如此,在什么条件下您会使用上述三种技术中的一种?

我对规范模式的看法:

  • 很好,因为它将业务/域需求隔离到可重用的组件中
  • 非常容易阅读,让代码说英语
  • 涉及相当多的代码(接口、抽象类)。如果我要使用它,我会将抽象放在一个通用程序集中(所以我的解决方案中没有一堆静态文件)。
  • 只需更改规范而不是服务层即可轻松更改需求。
  • 领域逻辑的最高可测试性(规范)

我对扩展方法(管道和过滤器)的看法:

  • 逻辑上的“重量级”,但仍然具有相同的简单性。
  • 将查询逻辑从服务层隔离到静态方法
  • 仍然需要排序的“反射”(检查提供的搜索参数并建立查询)
  • 允许您首先对架构(存储库、服务层)进行编码,而无需考虑特定的业务需求(在某些场景中很方便)

我对谓词方法的看法:

  • 可用于您需要对查询进行粗粒度控制的地方。
  • 适用于规格可能过度的小型项目

我最终的思考逻辑是,如果您正在处理一个复杂的业务应用程序,其中业务需求是预先知道的,但可能会随着时间的推移而改变,那么我会使用规范模式。

但是对于一个“启动”的应用程序,即需求会随着时间的推移而发展,并且有多种方法可以在没有复杂验证的情况下检索数据,我会使用 Pipes 和 Filters 方法。

你怎么认为?你们中的任何人在使用上述任何方法时遇到过问题吗?有什么建议吗?

即将开始一个新项目,因此这些类型的考虑因素至关重要。

谢谢您的帮助。

编辑以澄清规范模式

这是规范模式的相同用法。

Specification<Foo> someSpec; // Specification is an abstract class, implementing ISpecification<TEntity> members (And, Or, Not, IsSatisfiedBy).
someSpec = new AllFoosMustHaveABarSpecification(); // Simple class which inherits from Specification<Foo> class, overriding abstract method "IsSatisfiedBy" - which provides the actual business logic.    
ICollection<Foo> foos = fooDataService.GetFoosBySpecification(someSpec);
4

2 回答 2

2

根据我的一点经验:

  1. 用户需求总是在变化,我不知道为什么我的老板总是允许这种变化发生。所以+1规范
  2. 这里的程序员更像是“体力劳动者”,而不是“知识工作者”。你知道.. 那个整天打字的人。通过使用规范,我可以确保每个人都“输入”。这得到了我项目性质的支持。为了相同的目的,它需要许多不同的实现。不要问我为什么。
  3. 使用一种设计模式,它可以为您提供最高的模块化和灵活性,当然还有可测试性。这是一个小故事。
    在一个晴朗的日子里,我的伙伴告诉我,他写了一个类,使我们能够计算 32 种计算 X 的方式。而且他已经实现了所有这些。Hoho,我认为那是一个英雄式的编程。他花了几个星期在半夜这样做。他相信自己是一个优秀的程序员,所以他坚持让每个人都使用他的杰作。
    那时我们并不关心单元测试,所以我们使用了他的杰作。那时发生了什么?代码一直崩溃。好吧,从那时起,我意识到单元测试和模块化的重要性。
于 2010-08-27T02:42:50.563 回答
0

好吧,首先我会编写 Predicate 方法,即使它只用作其他两个的私有实现细节:

private ICollection<Foo> GetFoosBySpecification(Specification<Foo> spec) 
{ 
    return GetFooByPredicate(f => spec.IsSatisfiedBy(f));
} 

搜索参数函数将是一个类似的单行。

除此之外,我真的不能抽象地说什么。我必须更多地了解数据结构才能决定寻找它们的最佳方式。

于 2010-08-27T02:06:33.380 回答