設計パターン - Java における責任連鎖パターンの例 - 調達承認システム

シーン

発注書の承認

調達の承認は異なるレベルで行われます。つまり、購入金額の差に応じて、異なるレベルの監督者によって承認されます。

副会長は5万元から10万元(10万元を除く)の発注書を承認することができ、会長は10万元から50万元(50万元を除く)の発注書を承認することができます。

50万元以上の発注書については取締役会で審議、決定する必要がある。

Chain of Responsibility パターンが購入されていない場合は、次のように実装される可能性があります

public class PurchaseRequestHandler {
    public void sendRequestToDirector(int amount){
        if(amount<5000){
            this.handleByDirector();
        }else if(amount<10000){
            this.handleByVicePresident();
        }else if(amount<50000){
            this.handleByPresident();
        }else {
            this.handleByCongress();
        }
    }

    //主任审批采购单
    public void handleByDirector(){
        //代码省略
    }

    //副董事长审批采购单
    public void handleByVicePresident(){
        //代码省略
    }

    //董事长审批采购单
    public void handleByPresident(){
        //代码省略
    }

    //董事会审批采购单
    public void handleByCongress(){
        //代码省略
    }

}

問題があります

(1) PurchaseRequestHandler クラスは比較的大きく、各レベルの承認メソッドが 1 つのクラスに集中しているため、「単一責任の原則」に違反します。

テストと保守が難しい。

(2) 新たな承認レベルの追加、または任意のレベルの承認金額および承認内容の調整が必要な場合(例えば、会長の承認金額を60万元に変更する)

ソースコードを修正し、厳格なテストを実施する必要があるほか、一定レベルを削除する必要がある場合(たとえば、10万元以上の発注書は会長が直接承認する)、

副会長のポストが設置されなくなった場合もソースコードを修正する必要があり、これは「オープン・アンド・クローズの原則」に違反する。

(3) 承認プロセスの設定が硬直的であり、現在の承認プロセスは「取締役→副会長→会長→取締役会」となっており、必要に応じて承認が行われます。

「取締役→会長→取締役会」への変更 このソリューションではソースコードの修正のみで実現可能であり、クライアントによる承認プロセスのカスタマイズはできません。

責任連鎖パターン

責任連鎖のパターン:

リクエストの送信者と受信者の結合を避け、複数のオブジェクトがリクエストを受信し、これらのオブジェクトをチェーンに接続し、このチェーンに沿ってリクエストを渡すことができるようにします。

オブジェクトがそれを処理するまで。責任連鎖パターンは、オブジェクトの行動パターンです。

責任連鎖パターン構造図

責任連鎖パターンの役割

ハンドラー (抽象プロセッサー):

これはリクエストを処理するためのインターフェースを定義しており、通常は抽象クラスとして設計されています。異なる特定のハンドラーは異なる方法でリクエストを処理するため、

したがって、抽象リクエスト処理メソッドがその中に定義されています。各ハンドラーの次のホームは依然としてハンドラーであるため、抽象ハンドラーで定義されます。

次のホームへの参照としての、抽象プロセッサ タイプのオブジェクト (構造図内のサクセサなど)。この参照を通じて、ハンドラーをチェーンにリンクできます。

ConcreteHandler (特定のハンドラー):

ユーザーリクエストを処理できる抽象ハンドラのサブクラスであり、抽象ハンドラで定義された抽象リクエストの処理メソッドを具象ハンドラクラスに実装します。

リクエストを処理する前に、対応する処理権限があるかどうかを判断する必要があります。リクエストが処理できる場合は処理され、そうでない場合はリクエストは後続の権限に転送されます。

チェーン内の次のオブジェクトには、リクエストを転送するための特定のハンドラーでアクセスできます。Chain of Responsibility パターンでは、多くのオブジェクトが各オブジェクトに従属します。

引用が連鎖して連鎖を形成します。リクエストは、チェーン上のオブジェクトがリクエストの処理を決定するまで、チェーン上で渡されます。このリクエストをしたのは誰ですか

クライアントはチェーン上のどのオブジェクトが最終的にリクエストを処理するのかを知りません。これにより、システムはクライアントに影響を与えることなくチェーンを動的に再編成し、責任を割り当てることができます。

注記:

ブログ:
Domineering Rogue Temperament_C#、アーキテクチャ ロード、SpringBoot-CSDN ブログ

成し遂げる

上記の調達承認システムは責任連鎖モデルで導入されています。

1. 新しい注文書オブジェクトをリクエスト クラスとして作成します

import lombok.Data;

//采购单:请求类
@Data
public class PurchaseRequest {

    //采购金额
    private double amount;
    //采购单编号
    private int number;
    //采购目的
    private String purpose;

    public PurchaseRequest(double amount, int number, String purpose) {
        this.amount = amount;
        this.number = number;
        this.purpose = purpose;
    }

}

2. 新しい承認者クラスを抽象プロセッサとして作成します

//审批者类:抽象处理者
abstract class Approver {
    //定义后继对象
    protected Approver successor;
    //审批者姓名
    protected String name;

    public Approver(String name){
        this.name = name;
    }

    //设置后继者
    public void setSuccessor(Approver successor){
        this.successor = successor;
    }

    //抽象处理请求方法
    public abstract void processRequest(PurchaseRequest request);
}

3. 特定のプロセッサとして新しいディレクター クラスを作成します。

//主任类:具体处理者
public class Director extends Approver {

    public Director(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        //处理请求
        if(request.getAmount()<50000){
            System.out.println("主任"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+",元,采购目的:"+request.getPurpose());
        }else{
            //转发请求
            this.successor.processRequest(request);
        }
    }
}

4. 新しい副会長カテゴリーも作成します

//副董事长类:具体处理者
public class VicePresident extends Approver {

    public VicePresident(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        //处理请求
        if(request.getAmount()<100000){
            System.out.println("副董事长"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+",元,采购目的:"+request.getPurpose());
        }else{
            //转发请求
            this.successor.processRequest(request);
        }
    }
}

5. 新しいディレクタークラスも作成します

//董事长类:具体处理者
public class President extends Approver {

    public President(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        //处理请求
        if(request.getAmount()<500000){
            System.out.println("董事长"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+",元,采购目的:"+request.getPurpose());
        }else{
            //转发请求
            this.successor.processRequest(request);
        }
    }
}

6. 新しいボードクラスも作成します

//董事会类:具体处理者
public class Congress extends Approver {

    public Congress(String name) {
        super(name);
    }

    //具体请求处理方法
    public void processRequest(PurchaseRequest request) {
        //处理请求
        System.out.println("董事会"+this.name+"审批采购单:"+request.getNumber()+",金额:"+request.getAmount()+",元,采购目的:"+request.getPurpose());
    }
}

7. クライアント呼び出し方法

public class Client {
    public static void main(String[] args) {

        Approver zhuren,fudongshi,dongshi,dongshihui;
        zhuren = new Director("张主任");
        fudongshi = new VicePresident("李副董事长");
        dongshi = new President("王董事长");
        dongshihui = new Congress("董事会");

        //创建职责链
        zhuren.setSuccessor(fudongshi);
        fudongshi.setSuccessor(dongshi);
        dongshi.setSuccessor(dongshihui);

        //创建采购单
        PurchaseRequest pr1 = new PurchaseRequest(49000,1001,"购买网线");
        zhuren.processRequest(pr1);

        PurchaseRequest pr2 = new PurchaseRequest(89000,1002,"购买服务器");
        zhuren.processRequest(pr2);

        PurchaseRequest pr3 = new PurchaseRequest(190000,1003,"购买机柜");
        zhuren.processRequest(pr3);

        PurchaseRequest pr4 = new PurchaseRequest(600000,1004,"购买机房");
        zhuren.processRequest(pr4);

    }
}

8. まとめ

50,000 ~ 80,000 元(80,000 元を除く)の発注書を承認するマネージャー (Manager) ロールを追加するなど、システムに新しい特定のプロセッサーを追加する必要がある場合、

Approverクラスで定義された抽象処理メソッドを実装するには、抽象ハンドラクラスApproverのサブクラスとして、新たな固有ハンドラクラスManagerを記述する必要があります。

購入金額が 80,000 元以上の場合、リクエストは次の購入者に転送されます。

責任連鎖パターンの主な利点:

(1) Chain of Responsibility パターンにより、オブジェクトは他のどのオブジェクトがそのリクエストを処理するかを知る必要がなく、そのリクエストが処理されることだけを知る必要があります。

受信者も送信者も相手に関する明確な情報を持っておらず、チェーン内のオブジェクトはチェーンの構造を知る必要はなく、クライアントはチェーンの作成に責任を負います。

システムの結合度が低下します。

(2) 要求処理オブジェクトは、後続オブジェクトへの参照を維持するだけでよく、すべての候補ハンドラーへの参照を維持する必要はありません。

これにより、オブジェクトの相互接続が簡素化されます。

(3) オブジェクトに責任を割り当てる場合、責任チェーンは実行時に動的にチェーンを増やすことでより柔軟に対応できます。

または、リクエストを処理する責任を追加または変更するために変更します。

(4) 新しい特定のリクエスト ハンドラーをシステムに追加する場合、元のシステムのコードを変更する必要はなく、クライアント側でリンクを再確立するだけです。

この観点から見ると、「オープン・クローズの原則」に合致しています。

責任連鎖パターンの主な欠点は次のとおりです。

(1) リクエストには明確な受信者がないため、リクエストが処理されるという保証はなく、チェーンの終わりまでリクエストが処理されない可能性があります。

責任の連鎖が適切に構成されていないために、リクエストが処理されない場合もあります。

(2) 比較的長い責任チェーンの場合、リクエストの処理には複数の処理オブジェクトが関与する可能性があり、システムのパフォーマンスにある程度の影響を及ぼし、コードのデバッグには不便です。

(3) リンクが正しく確立されていない場合、循環呼び出しが発生し、システムが無限ループに陥る可能性があります。

該当するシーン:

(1) 同じリクエストを処理できるオブジェクトが複数あり、どのオブジェクトがリクエストを処理するかは実行時に決定され、クライアントはリクエストをチェーンに送信するだけで済みます。

リクエストが誰に対してどのように処理されているかを気にする必要はありません。

(2) 受信者を明示的に指定せずに、複数のオブジェクトの 1 つにリクエストを送信します。

(3) リクエストを処理するためにオブジェクトのグループを動的に指定でき、クライアントはリクエストを処理するための責任チェーンを動的に作成でき、チェーン内のプロセッサの順序を変更することもできます。

おすすめ

転載: blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/131917298