当前位置:网站首页>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 .
边栏推荐
- AI模型看看视频,就学会了玩《我的世界》:砍树、造箱子、制作石镐样样不差...
- Yintai department store ignites the city's "night economy"
- 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
- Dynamic programming (interval DP)
- 简单工厂和工厂方法模式
- Based on MCU, how to realize OTA differential upgrade with zero code and no development?
- . \vmware-vdiskmanager. exe -k “c:\\xxxxx.vmdk”
- Raven2 of vulnhub
- (database authorization - redis) summary of unauthorized access vulnerabilities in redis
- The world's most popular font editor FontCreator tool
猜你喜欢
Xiaopeng P7 hit the guardrail and the airbag did not pop up. The official responded that the impact strength did not meet the ejection requirements
vulnhub之GeminiInc
Numpy np. Max and np Maximum implements the relu function
同事写了一个责任链模式,bug无数...
This article explains the complex relationship between MCU, arm, MCU, DSP, FPGA and embedded system
Unity3D学习笔记5——创建子Mesh
Extrapolated scatter data
Vulnhub geminiinc
Excel快速跨表复制粘贴
Hongmeng fourth training
随机推荐
"Jianzhi offer 04" two-dimensional array search
Notes on 32-96 questions of sword finger offer
量化计算调研
mysql使用update联表更新的方法
The world's most popular font editor FontCreator tool
uniapp scroll view 解决高度自适应、弹框滚动穿透等问题。
MySQL union和union all区别
Vulnhub's Tomato (tomato)
Viewing binary bin files with notepad++ editor
《剑指offer 04》二维数组查找
cgroup简介
vulnhub之tomato(西红柿)
XML (DTD, XML parsing, XML modeling)
2022年湖南工学院ACM集训第二次周测题解
GCC compilation process and dynamic link library and static link library
金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
Solutions to the failure of installing electron
抓包整理外篇fiddler———— 会话栏与过滤器[二]
php 获取文件夹下面的文件列表和文件夹列表
剑指offer专项32-96题做题笔记