当前位置:网站首页>Colleagues wrote a responsibility chain model, with countless bugs
Colleagues wrote a responsibility chain model, with countless bugs
2022-07-03 11:53:00 【Manon breakthrough】
Click on the above “ Manon break through ”, Pay attention now
This is the first stop of manong charging , reply “666”, Get a special gift bag
True love, , Please set up “ Star standard ” Or click “ Looking at ”
Catalog
background
What is the chain of responsibility
Use scenarios
Conclusion
background
lately , I asked a member of the team to write an import function . He used the chain of responsibility model , The code heap is very large ,bug Many , It didn't achieve the effect I expected .
actually , For import function , I think the template method is more appropriate ! So , The team next door also presented our case , A collective code review.
Learn design patterns well , And not for practice , Force to use ! Let the original 100 The functions that can be realized by the line , Yes 3000 That's ok ! Right or wrong for the time being , Let's take a look at the responsibility chain design pattern !
What is the chain of responsibility
The responsibility chain pattern is a behavior design pattern , Allows you to send requests along the handler chain . Upon receipt of the request , Each handler can process the request , Or pass it on to the next handler on the chain .

Use scenarios
There are many scenarios for using the responsibility chain :
Multi conditional process judgment : Access control
ERP System process approval : The general manager 、 Personnel manager 、 project manager
Java The underlying implementation of the filter Filter
If you don't use this design pattern , So when the demand changes , It makes the code bloated or difficult to maintain , Take the following example .
| Counter example
Let's say there's a clearance game , The condition for entering the next level is that the score of the previous level is higher than xx:
The game has a total of 3 A level
Entering the second level requires the game score of the first level to be greater than or equal to 80
Entering the third level requires the game score of the second level to be greater than or equal to 90
So the code can write :
// The first level
public class FirstPassHandler {
public int handler(){
System.out.println(" The first level -->FirstPassHandler");
return 80;
}
}
// The second level
public class SecondPassHandler {
public int handler(){
System.out.println(" The second level -->SecondPassHandler");
return 90;
}
}
// The third level
public class ThirdPassHandler {
public int handler(){
System.out.println(" The third level -->ThirdPassHandler, This is the last level ");
return 95;
}
}
// client
public class HandlerClient {
public static void main(String[] args) {
FirstPassHandler firstPassHandler = new FirstPassHandler();// The first level
SecondPassHandler secondPassHandler = new SecondPassHandler();// The second level
ThirdPassHandler thirdPassHandler = new ThirdPassHandler();// The third level
int firstScore = firstPassHandler.handler();
// The score of the first level is greater than or equal to 80 Then enter the second level
if(firstScore >= 80){
int secondScore = secondPassHandler.handler();
// The score of the second level is greater than or equal to 90 Then enter the second level
if(secondScore >= 90){
thirdPassHandler.handler();
}
}
}
}So if the game has 100 Turn off , Our code will probably be written like this :
if( The first 1 Pass off ){
// The first 2 Turn off game
if( The first 2 Pass off ){
// The first 3 Turn off game
if( The first 3 Pass off ){
// The first 4 Turn off game
if( The first 4 Pass off ){
// The first 5 Turn off game
if( The first 5 Pass off ){
// The first 6 Turn off game
if( The first 6 Pass off ){
//...
}
}
}
}
}
}This code is not only redundant , And when we want to adjust some two levels, we will make very big changes to the code , The risk of this operation is high , therefore , The writing is very bad .
| Preliminary modification
How to solve this problem , We can connect each level through a linked list , The way to form a chain of responsibility , After the first pass, the second pass , After the second pass, the third pass ....
In this way, the client does not need to perform multiple operations if That's right :
public class FirstPassHandler {
/**
* The next level of the first level is The second level
*/
private SecondPassHandler secondPassHandler;
public void setSecondPassHandler(SecondPassHandler secondPassHandler) {
this.secondPassHandler = secondPassHandler;
}
// Score in this level game
private int play(){
return 80;
}
public int handler(){
System.out.println(" The first level -->FirstPassHandler");
if(play() >= 80){
// fraction >=80 And the next level exists before entering the next level
if(this.secondPassHandler != null){
return this.secondPassHandler.handler();
}
}
return 80;
}
}
public class SecondPassHandler {
/**
* The next level of the second level is The third level
*/
private ThirdPassHandler thirdPassHandler;
public void setThirdPassHandler(ThirdPassHandler thirdPassHandler) {
this.thirdPassHandler = thirdPassHandler;
}
// Score in this level game
private int play(){
return 90;
}
public int handler(){
System.out.println(" The second level -->SecondPassHandler");
if(play() >= 90){
// fraction >=90 And the next level exists before entering the next level
if(this.thirdPassHandler != null){
return this.thirdPassHandler.handler();
}
}
return 90;
}
}
public class ThirdPassHandler {
// Score in this level game
private int play(){
return 95;
}
/**
* This is the last pass , So there's no next level
*/
public int handler(){
System.out.println(" The third level -->ThirdPassHandler, This is the last level ");
return play();
}
}
public class HandlerClient {
public static void main(String[] args) {
FirstPassHandler firstPassHandler = new FirstPassHandler();// The first level
SecondPassHandler secondPassHandler = new SecondPassHandler();// The second level
ThirdPassHandler thirdPassHandler = new ThirdPassHandler();// The third level
firstPassHandler.setSecondPassHandler(secondPassHandler);// The next level of the first level is the second level
secondPassHandler.setThirdPassHandler(thirdPassHandler);// The next level of the second level is the third level
// explain : Because the third level is the last level , So there's no next level
// Start calling the first level Whether each level enters the next level Judge in each level
firstPassHandler.handler();
}
}| shortcoming
Disadvantages of existing models :
Each level has a member variable of the next level and is different , It's inconvenient to form a chain
The extensibility of the code is very bad
| Responsibility chain transformation
Since each level has a member variable of the next level and is different , Then we can abstract a parent class or interface on the level , Then each specific level inherits or implements .
A train of thought , Let's briefly introduce the basic composition of the responsibility chain design pattern :
Abstract processor (Handler) role : Define an interface to process requests , Contains abstract processing methods and a subsequent connection .
Specific handler (Concrete Handler) role : Implement the processing methods of the abstract processor , Determine whether the request can be processed , If the request can be processed, process , Otherwise, forward the request to its successor .
Customer class (Client) role : Create a processing chain , And submit the request to the specific handler object of the chain head , It doesn't care about processing details and the delivery of requests .

public abstract class AbstractHandler {
/**
* The next level uses the current abstract class to receive
*/
protected AbstractHandler next;
public void setNext(AbstractHandler next) {
this.next = next;
}
public abstract int handler();
}
public class FirstPassHandler extends AbstractHandler{
private int play(){
return 80;
}
@Override
public int handler(){
System.out.println(" The first level -->FirstPassHandler");
int score = play();
if(score >= 80){
// fraction >=80 And the next level exists before entering the next level
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
public class SecondPassHandler extends AbstractHandler{
private int play(){
return 90;
}
public int handler(){
System.out.println(" The second level -->SecondPassHandler");
int score = play();
if(score >= 90){
// fraction >=90 And the next level exists before entering the next level
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
public class ThirdPassHandler extends AbstractHandler{
private int play(){
return 95;
}
public int handler(){
System.out.println(" The third level -->ThirdPassHandler");
int score = play();
if(score >= 95){
// fraction >=95 And the next level exists before entering the next level
if(this.next != null){
return this.next.handler();
}
}
return score;
}
}
public class HandlerClient {
public static void main(String[] args) {
FirstPassHandler firstPassHandler = new FirstPassHandler();// The first level
SecondPassHandler secondPassHandler = new SecondPassHandler();// The second level
ThirdPassHandler thirdPassHandler = new ThirdPassHandler();// The third level
// Compared with the unchanged client code above , Only here set Method changes , Everything else is the same
firstPassHandler.setNext(secondPassHandler);// The next level of the first level is the second level
secondPassHandler.setNext(thirdPassHandler);// The next level of the second level is the third level
// explain : Because the third level is the last level , So there's no next level
// Start at the first level
firstPassHandler.handler();
}
}| Chain of responsibility factory transformation
For the above request chain , We can also maintain this relationship in the configuration file or an enumeration . I will use enumeration to teach you how to dynamically configure the request chain and form a call chain for each requester .

public enum GatewayEnum {
// handlerId, Interceptor name , Fully qualified class name ,preHandlerId,nextHandlerId
API_HANDLER(new GatewayEntity(1, "api Interface current limiting ", "cn.dgut.design.chain_of_responsibility.GateWay.impl.ApiLimitGatewayHandler", null, 2)),
BLACKLIST_HANDLER(new GatewayEntity(2, " black block ", "cn.dgut.design.chain_of_responsibility.GateWay.impl.BlacklistGatewayHandler", 1, 3)),
SESSION_HANDLER(new GatewayEntity(3, " User session interception ", "cn.dgut.design.chain_of_responsibility.GateWay.impl.SessionGatewayHandler", 2, null)),
;
GatewayEntity gatewayEntity;
public GatewayEntity getGatewayEntity() {
return gatewayEntity;
}
GatewayEnum(GatewayEntity gatewayEntity) {
this.gatewayEntity = gatewayEntity;
}
}
public class GatewayEntity {
private String name;
private String conference;
private Integer handlerId;
private Integer preHandlerId;
private Integer nextHandlerId;
}
public interface GatewayDao {
/**
* according to handlerId Get configuration items
* @param handlerId
* @return
*/
GatewayEntity getGatewayEntity(Integer handlerId);
/**
* Get the first handler
* @return
*/
GatewayEntity getFirstGatewayEntity();
}
public class GatewayImpl implements GatewayDao {
/**
* initialization , The configured in the enumeration handler Initialize to map in , Easy access
*/
private static Map<Integer, GatewayEntity> gatewayEntityMap = new HashMap<>();
static {
GatewayEnum[] values = GatewayEnum.values();
for (GatewayEnum value : values) {
GatewayEntity gatewayEntity = value.getGatewayEntity();
gatewayEntityMap.put(gatewayEntity.getHandlerId(), gatewayEntity);
}
}
@Override
public GatewayEntity getGatewayEntity(Integer handlerId) {
return gatewayEntityMap.get(handlerId);
}
@Override
public GatewayEntity getFirstGatewayEntity() {
for (Map.Entry<Integer, GatewayEntity> entry : gatewayEntityMap.entrySet()) {
GatewayEntity value = entry.getValue();
// There is no last one handler Is the first
if (value.getPreHandlerId() == null) {
return value;
}
}
return null;
}
}
public class GatewayHandlerEnumFactory {
private static GatewayDao gatewayDao = new GatewayImpl();
// Provide static methods , Get the first one handler
public static GatewayHandler getFirstGatewayHandler() {
GatewayEntity firstGatewayEntity = gatewayDao.getFirstGatewayEntity();
GatewayHandler firstGatewayHandler = newGatewayHandler(firstGatewayEntity);
if (firstGatewayHandler == null) {
return null;
}
GatewayEntity tempGatewayEntity = firstGatewayEntity;
Integer nextHandlerId = null;
GatewayHandler tempGatewayHandler = firstGatewayHandler;
// Iterate through all handler, And link them
while ((nextHandlerId = tempGatewayEntity.getNextHandlerId()) != null) {
GatewayEntity gatewayEntity = gatewayDao.getGatewayEntity(nextHandlerId);
GatewayHandler gatewayHandler = newGatewayHandler(gatewayEntity);
tempGatewayHandler.setNext(gatewayHandler);
tempGatewayHandler = gatewayHandler;
tempGatewayEntity = gatewayEntity;
}
// Return to the first handler
return firstGatewayHandler;
}
/**
* Reflection materializes the specific handler
* @param firstGatewayEntity
* @return
*/
private static GatewayHandler newGatewayHandler(GatewayEntity firstGatewayEntity) {
// Gets the fully qualified class name
String className = firstGatewayEntity.getConference();
try {
// According to the fully qualified class name , Load and initialize the class , The static segment of this class will be initialized
Class<?> clazz = Class.forName(className);
return (GatewayHandler) clazz.newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
return null;
}
}
public class GetewayClient {
public static void main(String[] args) {
GetewayHandler firstGetewayHandler = GetewayHandlerEnumFactory.getFirstGetewayHandler();
firstGetewayHandler.service();
}
}Conclusion
There are many design patterns , The chain of responsibility is just one of them , I think it's interesting , It's worth learning . Design pattern is really an art , Still need to work hard !
source :blog.csdn.net/q1472750149/article/
details/121886327
( End ) Code farmer breakthrough information link 1、 Oh my god ! Bytes to beat 《 Chinese Manual of algorithm 》 became angry , Full version PDF Open download !
2、 Computer basic knowledge summary and operating system PDF download
3、 Emma , Finally here !《LeetCode Java An explanation of the title of the edition 》.PDF
4、Github 10K+,《LeetCode Brush problem C/C++ Version answers 》 Baked .PDF
Welcome to add Yuge's personal wechat :smartfish2020, Join the fan group or circle of friends .边栏推荐
- vulnhub之presidential
- Machine learning 3.2 decision tree model learning notes (to be supplemented)
- 量化计算调研
- Momentum of vulnhub
- DNS多点部署IP Anycast+BGP实战分析
- Viewing binary bin files with notepad++ editor
- C language utf8toutf16 (UTF-8 characters are converted to hexadecimal encoding)
- 在CoreOS下部署WordPress实例教程
- vulnhub之momentum
- 金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
猜你喜欢

How should intermediate software designers prepare for the soft test

rxjs Observable filter Operator 的实现原理介绍

PHP Basics

vulnhub之GeminiInc v2

聊聊Flink框架中的状态管理机制

How to get started embedded future development direction of embedded

STL教程10-容器共性和使用场景

Kibana~Kibana的安装和配置

错排问题 (抽奖,发邮件)

The excel table is transferred to word, and the table does not exceed the edge paper range
随机推荐
PHP Basics
cgroup简介
Introduction to the implementation principle of rxjs observable filter operator
2022年中南大学夏令营面试经验
Excel quick cross table copy and paste
Qt OpenGL 纹理贴图
P3250 [hnoi2016] Network + [necpc2022] f.tree path tree section + segment tree maintenance heap
DNS多点部署IP Anycast+BGP实战分析
Hongmeng third training (project training)
vulnhub之momentum
DS90UB949
Cadence background color setting
vulnhub之tomato(西红柿)
Viewing binary bin files with notepad++ editor
ArcGIS application (XXI) ArcMap method of deleting layer specified features
Dynamically monitor disk i/o with ZABBIX
R language ggplot2 visualization: gganimate package creates dynamic line graph animation (GIF) and uses transition_ The reveal function displays data step by step along a given dimension in the animat
ORACLE进阶(一) 通过EXPDP IMPDP命令实现导dmp
Spl06-007 air pressure sensor (example of barometer)
Mysql根据时间搜索常用方法整理