共计 3645 个字符,预计需要花费 10 分钟才能阅读完成。
一、责任链模式介绍
1. 解决的问题
次要解决申请发送者和解决者的解耦问题。
2. 定义
责任链模式 是一种行为设计模式,容许将申请沿着解决者链进行发送。收到申请后,每个解决者均可对申请进行解决,或将其传递给链上的下个解决者。
3. 利用场景
- 当程序须要不同形式解决不同品种申请,而且申请类型和程序事后未知时,能够应用责任链模式。
- 当必须依照程序执行多个解决者时,能够应用责任链模式。
- 如果所需解决者及其程序必须在运行时进行扭转,能够应用责任链模式。
二、责任链模式优缺点
1. 长处
- 能够管制申请解决的程序。
- 繁多职责准则:可将发动申请和执行操作的类进行解耦。
- 开闭准则:能够在不更改现有代码的状况下在程序中新增解决者。
2. 毛病
- 局部申请可能未被解决。
三、责任链模式利用实例:申请中间件
1. 实例场景
在社区网站中,通常会给不同操作设置不同的权限。比方查看帖子不许任何权限,公布帖子须要验证用户是否登录,且用户是否为失常注册用户。
通常须要验证几个步骤:用户输出是否非法 -> 是否存在该用户 -> 用户状态是否失常。
明天,就以该场景为例来介绍责任链模式在申请中间件的应用。
2. 责任链模式实现
2.1 工程构造
chain-of-responsibilty-pattern | |
└─ src | |
├─ main | |
│ └─ java | |
│ └─ org.design.pattern.chain | |
│ ├─ Middleware.java | |
│ └─ impl | |
│ ├─ InputLegalMiddleware.java | |
│ ├─ UserExistMiddleware.java | |
│ └─ AccountActivatedMiddleware.java | |
└─ test | |
└─ java | |
└─ org.design.pattern.chain | |
└─ MiddlewareTest.java |
2.2 代码实现
2.2.1 中间件抽象类
/** | |
* 中间件抽象类 | |
*/ | |
public abstract class Middleware { | |
/** | |
* 下一个节点 | |
*/ | |
private Middleware next; | |
/** | |
* 设置下一个中间件节点 | |
* | |
* @param next 下一个中间件节点 | |
* @return Middleware | |
*/ | |
public Middleware setNext(Middleware next) { | |
this.next = next; | |
return this; | |
} | |
/** | |
* 验证 | |
* | |
* @param userId 用户 id | |
* @param email 邮箱 | |
* @return boolean | |
*/ | |
public boolean auth(String userId, String email) {if (ObjectUtils.isEmpty(next)) {return true;} | |
return next.auth(userId, email); | |
} | |
} |
2.2.2 中间件实现类
输出验证中间件
/** | |
* 输出验证中间件 | |
*/ | |
@Slf4j | |
public class InputLegalMiddleware extends Middleware { | |
/** | |
* 验证 | |
* | |
* @param userId 用户 id | |
* @param email 邮箱 | |
* @return boolean | |
*/ | |
@Override | |
public boolean auth(String userId, String email) { | |
// 模仿验证输出不非法 | |
if (ObjectUtils.isEmpty(userId) || ObjectUtils.isEmpty(email)) {log.error("输出不非法,用户{},邮箱{}", userId, email); | |
return false; | |
} | |
return super.auth(userId, email); | |
} | |
} |
用户存在中间件
/** | |
* 用户存在中间件 | |
*/ | |
@Slf4j | |
public class UserExistMiddleware extends Middleware { | |
/** | |
* 验证 | |
* | |
* @param userId 用户 id | |
* @param email 邮箱 | |
* @return boolean | |
*/ | |
@Override | |
public boolean auth(String userId, String email) { | |
// 模仿验证用户不存在 | |
if (!userId.equals("yiyufxst")) {log.error("用户 {} 不存在", userId); | |
return false; | |
} | |
return super.auth(userId, email); | |
} | |
} |
验证账户激活中间件
/** | |
* 验证账户激活中间件 | |
*/ | |
@Slf4j | |
public class AccountActivatedMiddleware extends Middleware { | |
/** | |
* 验证 | |
* | |
* @param userId 用户 id | |
* @param email 邮箱 | |
* @return boolean | |
*/ | |
@Override | |
public boolean auth(String userId, String email) { | |
// 模仿邮箱未验证激活 | |
if (!email.equals("yiyufxst@qq.com")) {log.error("用户 {} 邮箱 {} 未激活", userId, email); | |
return false; | |
} | |
return super.auth(userId, email); | |
} | |
} |
2.3 测试验证
2.3.1 测试验证类
@Slf4j | |
public class MiddlewareTest { | |
@Test | |
public void testMiddleware() { | |
// 输出非法 -> 用户存在 -> 账户已激活 | |
Middleware loginAuth = new InputLegalMiddleware().setNext(new UserExistMiddleware().setNext(new AccountActivatedMiddleware()) | |
); | |
boolean isLogin = loginAuth.auth("yiyu", ""); | |
Assert.assertFalse(isLogin); | |
isLogin = loginAuth.auth("yiyu", "xx"); | |
Assert.assertFalse(isLogin); | |
isLogin = loginAuth.auth("yiyufxst", "yiyufxst@xx.com"); | |
Assert.assertFalse(isLogin); | |
String userId = "yiyufxst"; | |
String email = "yiyufxst@qq.com"; | |
isLogin = loginAuth.auth(userId, email); | |
Assert.assertTrue(isLogin); | |
log.info("用户 {},邮箱{} 已激活,可失常应用", userId, email); | |
} | |
} |
2.3.2 测试后果
16:17:51.601 [main] ERROR o.d.p.c.impl.InputLegalMiddleware - 输出不非法,用户 yiyu,邮箱 | |
16:17:51.604 [main] ERROR o.d.p.chain.impl.UserExistMiddleware - 用户 yiyu 不存在 | |
16:17:51.604 [main] ERROR o.d.p.c.i.AccountActivatedMiddleware - 用户 yiyufxst 邮箱 yiyufxst@xx.com 未激活 | |
16:17:51.604 [main] INFO o.d.pattern.chain.MiddlewareTest - 用户 yiyufxst,邮箱 yiyufxst@qq.com 已激活,可失常应用 | |
Process finished with exit code 0 |
四、责任链模式构造
- 解决者(Handler)申明了所有具体解决者的通用接口。该接口通常仅蕴含单个办法用于申请解决,但有时还会蕴含一个设置链高低个解决者的办法。
-
根底解决者(Base Handler)是一个可选的类,能够将所有解决者专用的样本代码搁置在其中。
通常状况下,该类中定义了一个保留下个解决者援用的成员变量。客户端可通过将解决者传递给上个解决者的构造函数或设定办法来创立链。
-
具体解决者(Concrete Handlers)蕴含解决申请的理论代码。每个解决者接管到申请后,都必须决定是否进行解决,以及是否沿着链传递申请。
解决者通常是独立且不可变的,须要通过构造函数一次性地获取所有必要的数据。
- 客户端(Client)可依据程序逻辑一次性或动静地生存链。不过,申请可发送给链上任意一个解决者,而不是肯定要发给第一个解决者。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog
正文完