Application of responsibility chain model in business scenario

The responsibility chain model is a Design mode . In the responsibility chain model, many objects are connected by each object's reference to its next family to form a chain. Requests are passed along the chain until an object in the chain decides to process the request. The client sending the request does not know which object in the chain will eventually process the request, which makes the system dynamically reorganize and allocate responsibilities without affecting the client

-Baidu Encyclopedia

After writing the code for so many years, I have been adhering to the style of "invisible over tangible" to tired the code. I often go to the design pattern and try to find a cow B model to solve it and decouple the business code! The experience of our predecessors is always worth learning. As the old saying goes, "eat more salt than you eat". This time I just wrote a payment interface. After business analysis, I thought of the responsibility chain mode among the 23 design modes. Just can be used for reference!

Business requirements

There is a payment interface requirement, which can accept a variety of payment methods. For example: an order must pay 100 yuan, the client submitted a payment list, for example: cash: 50, sweep Alipay Code: 20, system red account payment: 30 yuan!

Normal thinking code implementation

Normally, when we realize this demand, we can directly

public void pay(List<payListDTO> payList) {
    
    for (payList as pay) {
    
        if (pay == "Wechat“) {
        
        }
    
         if (pay == "Alipay ") {
        
         }
    
         if (pay == "Code scanning payment“) {
        
        }
    }
}

The above code is very simple and clear! But as an older developer, it can't be tolerated! As for why I can't tolerate it, I don't show polite words here. There are many online!

Industry cohesion: "low, industry cohesion". Looking at the above code from this perspective, a good cohesion module (here you can see what is done in each if) should be a separate method or class to facilitate the reusability of the code. The release method becomes difficult to maintain with the iteration of requirements.

Then we try to use the accumulated wisdom of our predecessors to transform this code!

reform

  1. First, define a standard and define abstract methods
public abstract class Payhander {
    
    //Define payment behavior
    public abstract boolean pay(PayContext cnt)
}
  1. Define cash payment class implementation standards
@Component("cashPayHander")
class CashPayHander extends Payhander {

    public boolean pay(PayContext cnt) {
    
           //Cash payment logic
    }
}
  1. Define the implementation standard of balance payment class
@Component("balancePayHander")
class BalancePayHander extends Payhander {

    public boolean pay(PayContext cnt) {
    
         //Balance payment logic
    }
}

Defining interfaces and implementing classes are simple! So what's next is how to make use of these classes?

By understanding the description in the responsibility chain, we also define a reference to the next implementation class in each implementation class!

  1. Abstract interface under transformation
public abstract class Payhander {
    
    //Defines a reference to the next processor
    protected Payhander nextHander;
    
     
    // Here I add a new to-do class to implement the next reference injector
    public abstract void setNextHander(PayHander next)
     
        
    //Define getter s and setter s implemented by subclasses
    protected PayHander getNexthander() {
        return nextHeader;
    } 
        
        
        
        
        
    
    //Define payment behavior
    public abstract boolean pay(PayContext cnt)
}
  1. Cash payment realization under transformation
@Component("cashPayHander")
class CashPayHander extends Payhander {
    
    
    // Here, I use the injection method of Spring to realize automatic injection. At this time, the next reference of cash payment injection is balance payment
    @Resource
    @Override
    public void setNextHander(PayHander balancePayHander) {
        this.nextHander = balancePayHander;
    }
    
    
   
    
    public boolean pay(PayContext cnt) {
    
           //Cash payment logic
        
         if (super.getNexthander() != null) {
             //Call next processor
             super.getNexthander().pay(cnt);
         }
    }
}

The transformed classes of other classes are not illustrated here one by one!

After such a transformation, the rudiment of the responsibility chain appears in our mind. Each payment business logic makes business logic in each implementation class separately, and the utilization of a single class is improved. When adding other payment methods, just write the implementation and add it to the linked list.

Everything looks VeryGood, but there are also bad things!

shortcoming

  1. If the maintainer fails to handle the reference before each implementation class, it is easy to open a chain and loop.
  2. Each implementation class will be accessed once. This is the feature of linked list.

Tags: Java Programming Spring Design Pattern

Posted by varzosu on Sun, 17 Apr 2022 22:15:16 +0930