【问题标题】:Strategy or Command pattern?战略还是命令模式?
【发布时间】:2011-07-27 18:20:31
【问题描述】:

假设我有一个金融交易列表,我需要针对这些交易执行一个验证规则列表。一个例子是我有一笔购买产品的交易,但是首先我需要验证交易中的账户是否有足够的可用资金,产品没有售罄等。由于这些规则很多,交易将是标记为拒绝,并指定错误代码。

当然,我正在考虑在我的规则前面加上一个接口,允许执行代码滚动执行每个规则,直到第一个拒绝事务。

每个规则都需要配置参数(例如,ValidateMinimumBalance 需要知道 minimumBalance = 30)。规则执行的结果可以很简单,只需在交易对象上设置拒绝代码和错误代码;或者它可以像自动修改事务的多个其他属性一样复杂。

我对设计模式的基本理解指向策略模式或命令模式,但我不完全确定哪个更适合这种情况。

命令模式

  1. 每个命令都会实现某种 IValidate 接口
  2. 命令的构造函数将事务实例作为接收者,以便能够读取/验证事务以及修改事务的各个方面。构造函数还将采用键/值对数组作为验证逻辑的参数。

当我试图描绘策略模式如何适应这种情况时,它看起来非常相似。在大多数示例中,策略是具有单一方法的简单对象,但在我的情况下,策略将需要对事务的引用以及验证参数。

【问题讨论】:

  • 如果您认为这些规则会经常更改或业务用户需要访问它们,那么规则引擎也是一个可行的替代方案。你可以看看 JBoss Drools 或 IBM 的 iLog。

标签: c# java .net design-patterns architecture


【解决方案1】:

策略更多地用于交换算法,而不是真正用于链接验证。如果您打算使用一种模式,每种类型都有一个验证,那么您可以使用该策略,如果您发现必须使用多个验证器,或者需要重用验证器。我认为你要么必须找到一种新的方法来做到这一点(又名 COR),要么在你的策略中使用 COR。


我实际上会回答其他问题。我认为chain of responsibility patterncomposite patterndecorator for validators 的组合更适合您的需求。

现在输入一个示例实现.. 但在高级别

责任链 设计将围绕以下内容展开:

abstract class Handler
 {
   protected Handler next;
   
   public Handler(Handler h){
      this.next = h;
   }
   public abstract bool Validate(Request request); 
   public abstract void Handle(Request request);
}

class CoreLogic: Handler
{   
   public CoreLogic(Handler handle) : base(handle){

   }
   public override void Validate(Request request){
         return True
   }
   public override void Handle(Request request){
        if(this.Validate(request)){
            if(next!= null){
              next.Handle(request);
           }
        }

   }
}

class ValidBalance: Handler
{   
   public ValidBalance(Handler handle) : base(handle){

   }
   public override void Validate(Request request){
        return True
   }
   public override void Handle(Request request){
        if(this.Validate(request)){
            if(next!= null){
              next.Handle(request);
           }
        }
        
    }
}

class MainApp
{
   static void Main(){
       Handler h = new ValidateBalance( new CoreLogic(null));
       h.Handle(new Request());

   }
}

其他有用的链接:

Chain of Responsiblity wikipedia

【讨论】:

  • 我也正要建议责任链。此处的另一个链接:en.wikipedia.org/wiki/Chain-of-responsibility_pattern
  • 为什么你觉得在这种情况下责任链比命令模式更好?我看到的主要区别(除非我忽略了这一点)是调用者将使用命令负责循环遍历命令并执行每个命令。有了责任链,这似乎会自动发生。
  • 命令模式是一个抽象工具,更多地被设计为将执行命令的过程从接收器中分离出来。恕我直言,我认为它更多地是在与 UI 分离时使用的设计
  • 很公平。在我的例子中,所有验证者都有一个优先级,基本上决定了应该在链中首先调用哪个。我还将动态构建这些对象,因为并非所有对象都适用于所有类型的事务。似乎为了通过构造函数创建链,我必须首先创建最后一个对象。这是一个公平的评价吗?或者,我可以按照 James 下面的建议来代替使用构造函数进行链接。
【解决方案2】:

策略将用于“参数化”命令(告诉它应该如何执行操作的部分)。

【讨论】:

    【解决方案3】:

    当我尝试描绘策略模式如何适应这种情况时,它看起来非常相似。

    类似的?它应该看起来一样。

    区别在于上下文和委托的工作方式之一。原则上,Command 是“活动”代理。 策略 被注入到一些活动代理中。这种区别非常微妙。

    它几乎不会改变设计。改变的是期望。

    命令对象(或多或少)是独立的。他们生来就是为了做他们的工作,然后他们就会消失。没有人再关心他们了。也许他们也使用Memento模式,并且有一些未来的生活,但也许没有。

    策略对象(或多或少)与注入它们的对象一起存在。策略将是某个更大对象的一部分,并且可以被不同的实现替换,而不会破坏或更改任何其他内容。

    但基本界面基本相同。

    在大多数示例中,策略是具有单个方法的简单对象,

    这些都是糟糕的例子。

    但在我的例子中,策略需要引用交易以及验证参数。

    并不罕见。它没有错。

    【讨论】:

    • @S,Lott,所以看来我可以用两者完成同样的事情。不同之处在于,使用命令我将实例化每一个,将事务和验证参数作为构造函数的一部分传递。然后循环执行命令并调用 Validate。使用该策略,我将创建一个将验证参数传递给构造函数的实例。然而,事务本身很可能是 Validat(transaction) 方法的参数。除非我错过了您的观点,否则主要区别似乎是该命令包含对接收者的引用。
    【解决方案4】:

    但我不完全确定是哪一个 更适合这种情况

    两者都不是:) 我强烈建议查看Interpreter。实际上,您的验证者规则只是为您的交易制定的谓词。很可能很快您就需要将这些规则与 AND、OR、NOT 等结合起来。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-31
      • 1970-01-01
      • 1970-01-01
      • 2014-08-20
      • 2013-07-11
      • 1970-01-01
      • 2011-04-22
      相关资源
      最近更新 更多