2

我知道规范模式描述了如何使用实现的类层次结构ISpecification<T>来评估类型 T 的候选对象是否匹配某个规范(= 满足业务规则)。

我的问题:我要实现的业务规则需要评估几个对象(例如,客户和合同)。

我的双重问题:

  • 规范模式是否有典型的适应来实现这一点?我只能考虑删除ISpecification<T>我的规范类的实现,并在方法中获取尽可能多的参数isSatisfiedBy()。但是这样做,我失去了将这个规范与其他规范结合起来的能力。

  • 这个问题是否揭示了我的设计中的缺陷?(即我需要使用客户评估什么,而合同应该在另一个对象上评估,比如订阅,它可能包含所有必要的信息)?

4

4 回答 4

5

在那种情况下(取决于规范应该做什么,我将使用其中一个对象作为规范主题,将其他对象用作参数。

例子:

public class ShouldCreateEmailAccountSpecification : ISpecification<Customer>
{
    public ShouldCreateEmailAccountSpecification(Contract selectedContract)
    {
       SelectedContract = selectedContract;
    }

    public Contract SelectedContract { get; private set; }

    public bool IsSatisfiedBy(Customer subject)
    {
        return false;
    }
}
于 2010-02-24T22:40:27.767 回答
2

Paco 使用构造函数注入将一个对象作为主体,将一个对象作为参数的解决方案有时可以工作,但如果两个对象都是在规范对象之后构造的,这会使事情变得相当困难。

此问题的一种解决方案是使用参数对象,如以下重构建议:http: //sourcemaking.com/refactoring/introduce-parameter-object

基本思想是,如果您觉得 Customer 和 Contract 都是代表相关概念的参数,那么您只需创建另一个包含它们的参数对象。

public class ParameterObject  
{
    public Customer Customer { get; set; }
    public Contract Contract { get; set; }
}

然后,您的通用规范将变为该类型:

public class SomeSpecification : ISpecification<ParameterObject>
{
    public bool IsSatisfiedBy(ParameterObject candidate)
    {
        return false;
    }
}
于 2013-06-19T22:18:52.137 回答
2

您的问题是您的规范接口使用的是泛型类型参数,这会阻止它用于跨不同专业化(客户、合同)组合评估逻辑,因为 ISpecification<Customer> 实际上是与 ISpecification<Contract> 不同的接口。您可以使用上面 Jeff 的方法,它摆脱了类型参数并将所有内容作为基本类型(对象)传递。根据您使用的语言,您还可以将事物提升到一个级别,并使用委托将规范与布尔逻辑结合起来。C# 示例(在编写时不是特别有用,但可能会给您一些关于框架的想法):

ISpecification<Customer> cust_spec = /*...*/
ISpecification<Contract> contract_spec = /*... */
bool result = EvalWithAnd( () => cust_spec.IsSatisfiedBy(customer), () => contract_spec.IsSatisfiedBy( contract ) );

public void EvalWithAnd( params Func<bool>[] specs )
{
    foreach( var spec in specs )
    {
       if ( !spec() )
          return false; /* If any return false, we can short-circuit */
    }
    return true; /* all delegates returned true */
}
于 2010-02-24T16:56:11.443 回答
0

我不知道我是否理解你的问题。

如果您对 Customer 和 Contract 使用相同的规范,这意味着您可以向它们发送相同的消息。这可以通过使它们都实现一个接口并将该接口用作 T 类型来解决。我不知道这在您的领域是否有意义。

抱歉,如果这不是您问题的答案。

于 2010-03-27T18:42:09.513 回答