デザインパターンシリーズの記事
デザイン パターン (2、3): 創造的なファクトリー メソッドと抽象的なファクトリー パターン
デザインパターン (5): Creational Builder パターン
デザインパターン(13): 動作テンプレートメソッドパターン
1. デザインパターンの分類
- 創作パターン
- 「オブジェクトの作成方法」を説明するために使用され、その主な特徴は「オブジェクトの作成と使用の分離」です。
- シングルトン、プロトタイプ、ファクトリ メソッド、抽象ファクトリ、ビルダーを提供します
5 种创建型模式
- 構造パターン
- クラスまたはオブジェクトを特定のレイアウトでより大きな構造に編成する方法を説明するために使用されます。
- プロキシ、アダプター、ブリッジ、デコレーター、ファサード、フライウェイト、コンポジションが提供されます
7 种结构型模式
- 行動モデル
- 単一のオブジェクトだけでは実行できないタスクをクラスまたはオブジェクトが互いに連携して完了する方法と、責任を割り当てる方法を説明するために使用されます。
- テンプレートメソッド、ポリシー、コマンド、責任連鎖、状態、オブザーバー、メディエーター、イテレーター、ビジター、メメント、インタープリターを提供します
11 种行为型模式
2. 責任連鎖モデル
1。概要
- リクエストは複数のオブジェクトで処理できますが、各オブジェクトには異なる処理条件または権限があります。
- 例えば、会社員が休暇を申請した場合、休暇を承認できるリーダーは部門長、副部長、部長などです。
- ただし、各リーダーが承認できる日数は異なるため、従業員は休暇を申請したい日数に応じて、署名するリーダーを見つける必要があります。
- つまり、従業員は各リーダーの名前、電話番号、住所などの情報を覚えておく必要があり、難易度が高くなります。
意味
请求发送者
との多个请求处理者
カップリングを避けるために下一个对象的引用
前のオブジェクトからのリクエスト ハンドラーを記憶して、すべてのリクエスト ハンドラーをチェーンします。- リクエストが発生すると、オブジェクトがリクエストを処理するまで、リクエストはこのチェーンに沿って渡されます。
2. 構造
責任連鎖パターンには主に次の役割が含まれます。
- 抽象ハンドラー (Handler) ロール: 抽象処理メソッドと後続の接続を含む、リクエストを処理するためのインターフェースを定義します。
- 具象ハンドラ(Concrete Handler)の役割:抽象ハンドラの処理メソッドを実装し、リクエストが処理可能かどうかを判断し、リクエストを処理できる場合は処理し、そうでない場合はリクエストを後続のハンドラに転送します。
- クライアントクラス(Client)の役割:処理チェーンを作成し、その先頭の特定のプロセッサオブジェクトにリクエストを送信する 処理内容やリクエストの受け渡しプロセスは問わない
3. 実現する
休暇プロセス制御システムを開発する必要がある
一天
次の休暇は小组长
同意のみが必要です- 休職には同意が
1天到3天
必要です部门经理
- リクエストには
3天到7天
まだ总经理
同意する必要があります
クラス図は次のとおりです。
コードは次のとおりです。
- 休職
@Getter
@AllArgsConstructor
public class LeaveRequest {
//姓名
private String name;
//请假天数
private int num;
//请假内容
private String content;
}
- 抽象ハンドラクラス
public abstract class Handler {
protected final static int NUM_ONE = 1;
protected final static int NUM_THREE = 3;
protected final static int NUM_SEVEN = 7;
// 该领导处理的请求天数区间
private int numStart;
private int numEnd;
// 声明后续者(声明上级领导)
private Handler nextHandler;
public Handler(int numStart) {
this.numStart = numStart;
}
public Handler(int numStart, int numEnd) {
this.numStart = numStart;
this.numEnd = numEnd;
}
// 设置上级领导对象
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
// 各级领导处理请求条的方法
protected abstract void handleLeave(LeaveRequest leave);
// 提交请求条
public final void submit(LeaveRequest leave) {
// 该领导进行审批
this.handleLeave(leave);
// 如果还有上级 并且请假天数超过了当前领导的处理范围
if (this.nextHandler != null && leave.getNum() > this.numEnd) {
// 提交给上级领导进行审批
this.nextHandler.submit(leave);
} else {
System.out.println("流程结束!");
}
}
}
- 特定のプロセッサ
//小组长
public class GroupLeader extends Handler {
public GroupLeader() {
//小组长处理1-3天的请假
super(Handler.NUM_ONE, Handler.NUM_THREE);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("小组长审批:同意。");
}
}
//部门经理
public class Manager extends Handler {
public Manager() {
//部门经理处理3-7天的请假
super(Handler.NUM_THREE, Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("部门经理审批:同意。");
}
}
//总经理
public class GeneralManager extends Handler {
public GeneralManager() {
//部门经理处理7天以上的请假
super(Handler.NUM_SEVEN);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
System.out.println("总经理审批:同意。");
}
}
- クライアントテストクラス
public class Client {
public static void main(String[] args) {
//请假条来一张
LeaveRequest leave = new LeaveRequest("小花",5,"身体不适");
//各位领导
GroupLeader groupLeader = new GroupLeader();
Manager manager = new Manager();
GeneralManager generalManager = new GeneralManager();
groupLeader.setNextHandler(manager);//小组长的领导是部门经理
manager.setNextHandler(generalManager);//部门经理的领导是总经理
//提交申请
groupLeader.submit(leave);
}
}
4. メリットとデメリット
アドバンテージ
- モードは、
请求发送者
と の接收者
結合を低減します。 - システムの拡張性が強化され、必要に応じて新しいリクエスト処理クラスを追加できます。
满足开闭原则
- オブジェクトへの責任の割り当ての柔軟性が強化されました。ワークフローが変更された場合、チェーン内のメンバーを動的に変更したり、その順序を変更したり、責任を動的に追加または削除したりすることもできます。
- 各クラスは自分が処理すべき作業だけを処理すればよく、処理できない作業は次のオブジェクトに渡して完了させるなど、各クラスの責任範囲を明確にし、
符合类的单一职责原则
欠点がある
- 長い責任の連鎖に比べて、リクエストの処理には複数の処理オブジェクトが関与する可能性があり、システムのパフォーマンスにある程度の影響が生じます。
- 責任連鎖の確立の合理性はクライアントが保証するかどうかに依存しており、クライアントの複雑さが増大します。
- 循環呼び出しなどの責任連鎖の設定が間違っていると、システムエラーが発生する可能性があります
5. ソースコード分析
- JavaWeb アプリケーション開発では、FilterChain は責任連鎖 (フィルター) パターンの典型的なアプリケーションです。
以下は、Filter のシミュレーション実装分析です。
- Web リクエストのシミュレーション リクエストと Web レスポンス レスポンス
public interface Request{
}
public interface Response{
}
- アナログウェブフィルター フィルター
public interface Filter {
public void doFilter(Request req,Response res,FilterChain c);
}
- 具体的なフィルターの実装をシミュレートする
public class FirstFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器1 前置处理");
// 先执行所有前置处理再倒序执行所有后置处理
chain.doFilter(request, response);
System.out.println("过滤器1 后置处理");
}
}
public class SecondFilter implements Filter {
@Override
public void doFilter(Request request, Response response, FilterChain chain) {
System.out.println("过滤器2 前置处理");
// 先执行所有前置处理再倒序执行所有后置处理
chain.doFilter(request, response);
System.out.println("过滤器2 后置处理");
}
}
- フィルターチェーンの実装をシミュレートする FilterChain
public class FilterChain {
private List<Filter> filters = new ArrayList<Filter>();
private int index = 0;
// 链式调用
public FilterChain addFilter(Filter filter) {
this.filters.add(filter);
return this;
}
public void doFilter(Request request, Response response) {
if (index == filters.size()) {
return;
}
Filter filter = filters.get(index);
index++;
filter.doFilter(request, response, this);
}
}
- テストクラス
public class Client {
public static void main(String[] args) {
Request req = null;
Response res = null ;
FilterChain filterChain = new FilterChain();
filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
filterChain.doFilter(req,res);
}
}
输出结果:
过滤器1 前置处理
过滤器2 前置处理
过滤器2 后置处理
过滤器1 后置处理