責任デザインパターン連鎖


責任パターンの連鎖は、デザインパターンについてのG . O . Fブックからの行動パターンです、このパターンは非常にあなたがそのレシーバーから送付者を切り離す必要があるとき、そして、各々のレシーバーが果たすいくつかの責任があるとき、役に立ちます.
例えば、メールサーバーを持っているとして、スパム、ファン、ビジネスを特定する方法を確認して、メールを通常のメールから文句を言い、このメールをメールサーバーに実装するように求められます.
  • スパムは無視する必要があります.
  • ファンのメールは会社のCEOに直接転送する必要があります.
  • ビジネスメールは、企業の電子メールに転送する必要があります.
  • 苦情メールは、消費者部門に向けられる必要があります.
  • 今、我々は単に我々の論理のチェックをして、必要条件を達成するならば、我々は単に入れられることができます、しかし、それは問題です
    理由
  • 新しい規則を追加する必要があるときはいつでも、我々は我々の機能を変えるでしょう.
  • 私たちはまた、その機能がその多くのことをしているように、単一の責任原則を破ります
    独自.
  • より良いアプローチは、それぞれの責任のために異なったハンドラー、すなわちスパム、ファンをフィルタリングして、それからいくつかの方法を一緒に結合します.これはCORが私たちを助けるのです.このパターンの実装を見てみましょう.

    Let's refer the Chain of responsibility pattern with COR now on wards.



    こちらです.MailFilter 抽象インターフェイスfilter 次に、具体的なクラスごとに実装されます.SpamFilter , FanFilter , したがって、各フィルタは、フィルタロジックの独自の実装を提供します.MailServer クラスは、それに割り当てられたハンドラーにメールオブジェクトを送る送付者クラスです.そして、実際の実装で、それが1つ以上のハンドラがあるかどうか、そして、それがどのハンドラを相互作用しているかどうか知りません.

    実装


    実装のために抽象クラスの代わりに機能インターフェースを選びましたMailHandler 一つは抽象的な方法しかないからです.
    
    @FunctionalInterface
    public interface MailFilter {
        default MailFilter appendNext(MailFilter next) {
            return mail -> {
                filter(mail);
                next.filter(mail);
            };
        }
    
        void filter(Mail mail);
    }
    
    注意appendNext 関数は、同じインタフェース(呼び出し元)を呼び出し元に返します.filter メソッド(具体的なクラスである)next.filter(mail) チェーンの次のハンドラーのメソッド.
    さて、このインターフェイスの具体的な実装の一つを見てみましょうSpamFilter
    class SpamFilter implements MailFilter{
        private final List<String> allowedMails = Arrays.asList(
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]"
        );
    
        @Override
        public void filter(Mail mail) {
            if(isSpam(mail)) {
                System.out.println("Ignoring spam mail");
            }
        }
    
        private boolean isSpam(Mail mail) {
            return !allowedMails.contains(mail.from());
        }
    }
    
    ご覧の通りSpamFilter クラスはMailFilter インターフェースなので、filter 次に、Mail オブジェクトをフィルタリングすることができます.

    The filtering logic in above example is just for demo purpose, please don't use it in production :)


    同様に、そのプロセスを処理するチェーン内の他のフィルタも存在するMail 論理/条件が通るならば、オブジェクトとそれに取り組む.どのようにそれが送付者/クライアントによって使われているか見ましょう.
    class MailServer {
        private final MailFilter filter;
    
        public MailServer() {
            filter = init();
        }
    
        private MailFilter init() {
            return new SpamFilter()
                    .appendNext(new FanFilter())
                    .appendNext(new BusinessFilter());
        }
    
        public void process(List<Mail> mails) {
            mails.forEach(filter::filter);
        }
    }
    
    ここではデモの目的のために私は同じクラスのチェーンを定義するために選択しているが、実際のシナリオでは、する必要があります
    このチェーンを生成し、あなたを与えるいくつかの戦略や工場filter あなたのコードで扱うオブジェクト.ここでは、私たちはprocess メールのリストを受信して1つずつ処理する方法.
    これはあなたのコードの他のチェーンの場合よりもはるかにクリーナーな解決策であり、また
    この場合のハンドラ/フィルタ(例えば)、例えば、チェーンを初期化するために別々のクラスがあるならばMailServerクラスはメールオブジェクトがどれくらいのフィルタを通過するかさえ知らないでしょう
    チェーンからいつでも触れずにMailServer クラス.
    また、すべてのフィルタ論理はそれ自身のクラスに存在します.

    欠点


    ソフトウェア世界のすべてのものと同様に、このパターンはまた、魔法の弾丸ではなく、コンズと来る
  • チェーンが非常に長いなら、問題がどこにあるかをデバッグして、確認するのは難しいです.
  • ハンドラの非常に長いチェーンでは、呼び出しスタックも同様に成長し、パフォーマンスの問題につながる可能性があります.
  • 重複を避けることができますが、ハンドラの間でコードを複製することができます.
  • 考慮すべき点

  • 要求オブジェクトがすべてのハンドラで実行されなければならないという保証を必要としないとき、それを使用してください
    デコレータパターン.
  • 複数のハンドラがリクエストオブジェクトを処理することができなければならないときに使用し、送信者にどんなアイデアを持っていても構わない
    複数のハンドラについて
  • クライアントが要求を実行するハンドラを知らなければならないとき、それを使用しないでください.
  • 結論


    CORデザインパターンは、そのレシーバーから送付者を切り離すのを助けます
    それを知っている送付者なしで複数のハンドラまたはレシーバーは、それから、送付者のコードに触れることなくレシーバーを取り除くか、加えるために柔軟性を与えます.javax.servlet.Filter APIはJava Worldで実装されているパターンの良い例です.このパターンの別の良いケースはログオンしています.wikipedia 実装でこの例を挙げてください.しかし、開発者として、我々はこれらを意識しなければならないように、Corパターンもその欠点を持ちます.
    あなたは私の上で同じを読むかもしれませんpersonal blog .

    参考文献

  • Chain of Responsibility pattern wikipedia
  • Head First Design Pattern book
  • Source code for above example