1. 定義
Chain of Responsibility パターンは、要求を処理チェーンに送信し、各プロセッサがそれを処理して、完了したら次のプロセッサに渡すことができる動作設計パターンです。
- リクエストが処理される順序を制御できます
- 単一責任の原則により、操作を開始するクラスと操作を実行するクラスを切り離すことができます
- オープンとクローズの原則により、元の業務コードを変更せずに他の処理クラスを追加できます
- すべてのハンドラーが実行できるという保証はありません
- 効率はあまり良くない、気をつけて電話しないと色々と問題が発生する
2. 使用シーン
- 複数のハンドラを順番に実行する必要がある場合は、Chain of Responsibility パターンの使用を検討してください
- ハンドラーの順序とその順序を実行時に変更する必要がある場合は、責任の連鎖パターンの使用を検討してください。
実用化:
- Apache Tomcat の Encoding エンコーディング処理の処理
- SpringBoot のインターセプターとフィルター チェーン
- netty での処理チェーン
- 支払リスク管理メカニズム
- ログ処理レベル
3. Java での簡単なアプリケーション
使用シーン:
休暇申請制度を例にとると、チームリーダー→ディレクター→大臣という連鎖が形成され、
従業員が休暇申請を提出した後、それを処理できるオブジェクトができるまで、この連鎖に沿って要求が渡されます。
5 日間の休暇申請は、最初にチーム長に届き、
チーム長には承認権限がなく、上司 (取締役) に申請が渡されます。
部長には承認権限があるため、上司
として休暇申請に同意します。スタッフは最終的な決定を気にする必要はありません. 誰が承認し、リクエストを送信するだけで済みます.
3.1 抽象処理インターフェース
/**
* @Author charles.yao
* @Description 抽象处理者
* @Date 2022/12/21 15:32
*/
public interface Hanlder {
/**
* 处理员工请假天数
* @param name
* @param holidayDay
*/
public abstract void handleRequest(String name, Integer holidayDay);
}
3.2 特定の処理ロジックを実現するために、チームリーダー、ディレクター、大臣の 3 つの特定の処理者を作成する
/**
* @Author charles.yao
* @Description 组长处理者
* @Date 2022/12/21 15:34
*/
public class PmHandler extends Hanlder {
@Override
public void handleRequest(String name, Integer holidayDay) {
if (holidayDay <= 3) {
System.out.println(name + "组长已经批准假期");
} else {
if (getNext() != null) {
getNext().handleRequest(name,holidayDay);
}else {
System.out.println("请假天数太多,申请被驳回");
}
}
}
}
/**
* @Author charles.yao
* @Description 部门经理处理者
* @Date 2022/12/21 15:37
*/
public class MinisterHandler extends Hanlder{
@Override
public void handleRequest(String name, Integer holidayDay) {
if (holidayDay <= 15) {
System.out.println(name + "部门经理已经批准假期");
} else {
if (getNext() != null) {
getNext().handleRequest(name,holidayDay);
}else {
System.out.println("请假天数太多,申请被驳回");
}
}
}
}
/**
* @Author charles.yao
* @Description 总监处理者
* @Date 2022/12/21 15:37
*/
public class DirectorHandler extends Hanlder{
@Override
public void handleRequest(String name, Integer holidayDay) {
if (holidayDay <= 7) {
System.out.println(name + "总监已经批准假期");
} else {
if (getNext() != null) {
getNext().handleRequest(name,holidayDay);
}else {
System.out.println("请假天数太多,申请被驳回");
}
}
}
}
テストクラス
/**
* @Author charles.yao
* @Description
* @Date 2022/12/21 15:39
*/
public class OaTest1 {
public static void main(String[] args) {
Hanlder pmHandler = new PmHandler();
Hanlder directorHandler = new DirectorHandler();
Hanlder ministerHandler = new MinisterHandler();
pmHandler.setNext(directorHandler);
directorHandler.setNext(ministerHandler);
pmHandler.handleRequest("张三",14);
}
}
運用実績
张三部门经理已经批准假期
上記の簡単な小さなデモを通じて、一連の問題を見つけます。特定のプロセッサの増加、減少、または調整順序が責任のチェーン全体の調整と再構築を伴うが、不必要な作業負荷が増加する場合、上記を実行します。書き込み改善、改善は以下の通り、
-
- 抽象ハンドラで次の参照をキャンセルする
- 独立した一連の責任クラス:
- 特定のハンドラーを追加する add メソッドを提供し、List に基づいて目に見えない責任の連鎖を構築します。
- 抽象ハンドラーのリクエスト処理メソッドを実装し、責任チェーン内の特定のハンドラーをトラバースして、リクエストの配信と処理を実現します
// 抽象处理者
public interface Handler {
public abstract void handleRequest(String name, int days);
}
// 具体处理者
public class PMHandler implements Handler {
@Override
public void handleRequest(String name, int days) {
if (days <= 3) {
System.out.println(name +",组长已经同意您的请假审批!");
}
}
}
public class DirectorHandler implements Handler {
@Override
public void handleRequest(String name, int days) {
if (days <= 7) {
System.out.println(name + ",中心总监已经同意您的请假审批");
}
}
}
public class MinisterHandler implements Handler {
@Override
public void handleRequest(String name, int days) {
if (days <= 15) {
System.out.println(name + ",部长已经同意您的请假审批");
}
}
}
// 责任链类
public class HandlerChain implements Handler {
private List<Handler> handlerList;
public HandlerChain() {
this.handlerList = new ArrayList<>();
}
public HandlerChain addHandler(Handler handler) {
handlerList.add(handler);
return this;
}
@Override
public void handleRequest(String name, int days) {
for (Handler handler : handlerList) {
handler.handleRequest(name, days);
}
}
}
// 客户类
public class OASystem {
public static void main(String[] args) {
// 创建具体处理者
Handler pm = new PMHandler();
Handler director = new DirectorHandler();
Handler minister = new MinisterHandler();
// 构建责任链
HandlerChain chain = new HandlerChain()
.addHandler(pm)
.addHandler(director)
.addHandler(minister);
// 使用责任链
chain.handleRequest("王二", 10);
}
}
次に、責任連鎖モードを使用するために springboot を使用します。
使用シーン:
ユーザーは、注文前に作業を確認し、ユーザーの注文状況を順番に取得する必要があります。
seqId を使用して、顧客が繰り返し注文したかどうかを確認します
リクエスト パラメータが正当かどうかを確認し、顧客の
銀行口座を取得します
注文エンティティ:
/**
* @Author charles.yao
* @Description 订单实体类
* @Date 2023/1/28 14:58
*/
@Data
public class OrderContext {
/**
* 请求唯一序列ID
*/
private String seqId;
/**
* 用户ID
*/
private String userId;
/**
* 产品skuId
*/
private Long skuId;
/**
* 下单数量
*/
private Integer amount;
/**
* 用户收货地址ID
*/
private String userAddressId;
}
注文検証抽象インターフェース OrderHandleIntercept
/**
* @Author charles.yao
* @Description 订单处理结果类
* @Date 2023/1/28 15:04
*/
public interface OrderHandleIntercept {
/**
* 指定处理顺序
* @return
*/
int sort();
/**
* 订单处理
* @param orderContext
* @return
*/
OrderAddContext handle(OrderAddContext orderContext);
}
繰り返し注文のロジック検証
/**
* @Author charles.yao
* @Description 用于重复下单的逻辑验证
* @Date 2023/1/28 15:24
*/
@Component
public class RepeatOrderHandleInterceptService implements OrderHandleIntercept{
@Override
public int sort() {
return 1;
}
@Override
public OrderAddContext handle(OrderAddContext orderContext) {
System.out.println("通过orderId 校验客户是否重复下单");
return orderContext;
}
}
リクエストパラメータが正当かどうかを検証するために使用されます
/**
* @Author charles.yao
* @Description 用于验证请求参数是否合法
* @Date 2023/1/28 15:28
*/
@Component
public class ValidOrderHandleInterceptService implements OrderHandleIntercept{
@Override
public int sort() {
return 2;
}
@Override
public OrderAddContext handle(OrderAddContext orderContext) {
System.out.println("检查请求参数,是否合法,并且获取客户的银行账户");
return orderContext;
}
}
お客様の口座残高が十分かどうかを確認するために使用されます
/**
* @Author charles.yao
* @Description 用于检查客户账户余额是否充足
* @Date 2023/1/28 15:31
*/
@Component
public class BankOrderHandleInterceptService implements OrderHandleIntercept{
@Override
public int sort() {
return 3;
}
@Override
public OrderAddContext handle(OrderAddContext orderContext) {
System.out.println("检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额");
return orderContext;
}
}
注文確認マネージャー
/**
* @Author charles.yao
* @Description 订单验证管理器
* @Date 2023/1/28 15:49
*/
@Component
public class OrderHandleChainService implements ApplicationContextAware {
private List<OrderHandleIntercept> handleList = new ArrayList<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, OrderHandleIntercept> orderHandleInterceptMap = applicationContext.getBeansOfType(OrderHandleIntercept.class);
handleList = orderHandleInterceptMap.values().stream()
.sorted(Comparator.comparing(OrderHandleIntercept::sort))
.collect(Collectors.toList());
}
public OrderAddContext execute(OrderAddContext context) {
for (OrderHandleIntercept orderHandleIntercept : handleList) {
orderHandleIntercept.handle(context);
}
return context;
}
}
テストクラス
/**
* @Author charles.yao
* @Description 订单测试类
* @Date 2023/1/28 16:07
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class CalculatorServiceTest {
@Autowired
private OrderHandleChainService orderHandleChainService;
@Test
public void test(){
orderHandleChainService.execute(new OrderAddContext());
}
}
試験結果
2023-01-28 16:10:01.484 INFO 38155 --- [ main] c.y.d.c.CalculatorServiceTest : Starting CalculatorServiceTest using Java 1.8.0_212 on localhost with PID 38155 (started by yaoyonghao in /Users/yaoyonghao/Documents/workProject/design-pattern)
2023-01-28 16:10:01.487 INFO 38155 --- [ main] c.y.d.c.CalculatorServiceTest : No active profile set, falling back to 1 default profile: "default"
2023-01-28 16:10:02.540 INFO 38155 --- [ main] c.y.d.c.CalculatorServiceTest : Started CalculatorServiceTest in 1.548 seconds (JVM running for 3.081)
通过orderId 校验客户是否重复下单
检查请求参数,是否合法,并且获取客户的银行账户
检查银行账户是否合法,调用银行系统检查银行账户余额是否满足下单金额
もちろん、 @Order() アノテーションを使用して実行順序を制御することもできます