Strategy or Command pattern?

2020-06-23 08:14发布

Assuming I have a list of financial transactions, I have a need to execute a list of validation rules against those transactions. An example would be I have a transaction to purchase a product, however first I need to validate that the account in the transaction has enough available funds, that the product is not sold out etc. As a result of these many rules the transaction will be marked as rejected, as well as an error code should be specified.

Naturally I am thinking towards fronting my rules with an interface, allowing the executing code to roll through the rules executing each one until the first one rejects the transaction.

Each rule will require to be configured with parameters (ex. ValidateMinimumBalance will need to know that minimumBalance = 30). The result of a rule executing can be as simple as settings the rejection code on the transaction object, and the error code; or it can be as complicated as automatically modifying multiple other properties of the transaction.

My basic understanding of design patterns points to me either Strategy or Command patterns, but I am not entirely sure which one is better suited for this scenario.

Command Pattern

  1. Each command will implement some sort of IValidate interface
  2. The constructor of the command will take an instance of the transaction as the receiver in order to be able to read/validate the transaction as well as modify aspects of it. The constructor will also take an array of key/value pairs as parameters for the validation logic.

When I try to picture how the Strategy Pattern fits this scenario it looks very similar. In most examples the strategy is a simple object with a single method, however in my case the strategy will need a reference to the transaction as well as validation parameters.

4条回答
对你真心纯属浪费
2楼-- · 2020-06-23 08:33

Strategy is more used to swap out algorithms, its not really used for chaining validations. If you are going to have a pattern where you have one validation per type then you could use the strategy, if you are finding your having to use multiple validators, or the need to reuse validators. I think you are going to have to either find a new way to do it (aka COR) or within your strategy use the COR.


I actually would answer other. I think a combination chain of responsibility pattern and the composite pattern, or decorator for validators is much more suited for your needs.

Typing up an example implementation now.. but at a high level

Chain of Responsiblity The design would revolve around something like:

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());

   }
}

Other useful links:

Chain of Responsiblity wikipedia

查看更多
smile是对你的礼貌
3楼-- · 2020-06-23 08:41

When I try to picture how the Strategy Pattern fits this scenario it looks very similar.

Similar? It should look identical.

The distinction is one of how the context and delegation works. In principle a Command is the "active" agent. A Strategy is injected into some active agent. That distinction is pretty subtle.

It barely changes the design. What does change is the expectation.

Command objects (more-or-less) stand alone. They're built to do their work, and then they can vanish. No one cares about them any more. Perhaps they also use the Memento pattern, and have some future life, but perhaps not.

Strategy objects (more-or-less) live with the object into which they're injected. A Strategy would be part of some larger object, and could be replaced by a different implementation without breaking or changing anything else.

But the essential interface is largely the same.

In most examples the strategy is a simple object with a single method,

Those are poor examples.

however in my case the strategy will need a reference to the transaction as well as validation parameters.

Not unusual. Nothing wrong with it.

查看更多
手持菜刀,她持情操
4楼-- · 2020-06-23 08:47

A Strategy would be something use to 'parameterize' a Command (telling it how parts of the operation should be executed).

查看更多
▲ chillily
5楼-- · 2020-06-23 08:51

but I am not entirely sure which one is better suited for this scenario

Neither :) I strongly recommend to look at Interpreter. Actually your validator rules are just predicates formulated for your transactions. It's quite possible that soon you will need to combine these rules with AND, OR, NOT, etc.

查看更多
登录 后发表回答