如何调整规范模式来评估对象的组合?

发布于 2024-08-23 00:11:25 字数 407 浏览 5 评论 0原文

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

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

我的双重问题:

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

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

I know that the Specification pattern describes how to use a hierarchy of classes implementing ISpecification<T> to evaluate if a candidate object of type T matches a certain specification (= satisfies a business rule).

My problem : the business rule I want to implement needs to evaluate several objects (for example, a Customer and a Contract).

My double question :

  • Are there typical adaptations of the Specification patterns to achieve this ? I can only think of removing the implementation of ISpecification<T> by my specification class, and taking as many parameters as I want in the isSatisfiedBy() method. But by doing this, I lose the ability to combine this specification with others.

  • Does this problem reveal a flaw in my design ? (i.e. what I need to evaluate using a Customer and a Contract should be evaluated on another object, like a Subscription, which could contain all the necessary info) ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一刻暧昧 2024-08-30 00:11:25

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

示例:

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

    public Contract SelectedContract { get; private set; }

    public bool IsSatisfiedBy(Customer subject)
    {
        return false;
    }
}

In that case (depending on what the specification precisely should do, I would use one of the objects as specification subject and the other(s) as parameter.

Example:

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

    public Contract SelectedContract { get; private set; }

    public bool IsSatisfiedBy(Customer subject)
    {
        return false;
    }
}
踏雪无痕 2024-08-30 00:11:25

您的问题是您的规范接口使用通用类型参数,这阻止了它用于组合不同专业化(客户、合同)之间的评估逻辑,因为 ISpecification实际上是与 ISpecification不同的接口。您可以使用上面 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 */
}

Your problem is that your specification interface is using a generic type parameter, which prevents it from being used for combining evaluation logic across different specializations (Customer,Contract) because ISpecification<Customer> is in fact a different interface than ISpecification<Contract>. You could use Jeff's approach above, which gets rid of the type parameter and passes everything in as a base type (Object). Depending on what language you are using, you may also be able to pull things up a level and combine specifications with boolean logic using delegates. C# Example (not particularly useful as written, but might give you some ideas for a framework):

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 */
}
终难愈 2024-08-30 00:11:25

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;
    }
}

Paco's solution of treating one object as the subject and one as a parameter using constructor injection can work sometimes but if both objects are constructed after the specification object, it makes things quite difficult.

One solution to this problem is to use a parameter object as in this refactoring suggestion: http://sourcemaking.com/refactoring/introduce-parameter-object.

The basic idea is that if you feel that both Customer and Contract are parameters that represent a related concept, then you just create another parameter object that contains both of them.

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

Then your generic specification becomes for that type:

public class SomeSpecification : ISpecification<ParameterObject>
{
    public bool IsSatisfiedBy(ParameterObject candidate)
    {
        return false;
    }
}
番薯 2024-08-30 00:11:25

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

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

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

I don't know if I understood your question.

If you are using the same specification for both Customer and Contract, this means that you can send the same messages to both of them. This could be solved by making them both to implement an interface, and use this interface as the T type. I don't know if this makes sense in your domain.

Sorry if this is not an answer to your question.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文