【デザインパターン】Chain of Responsibility

どんなもの?

  • 一つ以上のオブジェクトに要求を処理する機会を与えることで、要求の送り手と受け取り手を疎結合にする
  • 受け取り手を繋いで、その連結順に要求を受け渡していく
  • 要求を処理するオブジェクトを意識しないで、要求を送ることができる

どんなときに使う?

典型的な構成要素

  • Handler
    • 要求を処理するインターフェースを定義する
    • 自身で処理できない要求を受け流す先を格納するフィールドを定義する
  • ConcreteHandler
    • Handlerのインターフェースを実装する。
    • 実際に要求を処理するクラス
  • Client

コード

#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;

class Handler{
public:
  Handler(){
    next = 0;
  }
  void setNext(Handler *n){
    next = n;
  }
  void add(Handler *n){
    if(next){
      next->add(n);
    }else{
      next = n;
    }
  }
  virtual void handle(int i){
    next->handle(i);
  }
private:
  Handler *next;
};

class ConcreteHandlerA: public Handler{
public:
  void handle(int i)
  {
    if(rand() % 3)
    {
      cout << "HandlerA passed " << i << " ";
      Handler::handle(i);
    }else{
      cout << "HandlerA handled " << i << " ";
    }
  }
};

class ConcreteHandlerB: public Handler{
public:
  void handle(int i)
  {
    if(rand() % 3)
    {
      cout << "HandlerB passed " << i << " ";
      Handler::handle(i);
    }else{
      cout << "HandlerB handled " << i << " ";
    }
  }
};

class ConcreteHandlerC: public Handler{
public:
  void handle(int i)
  {
    if(rand() % 3)
    {
      cout << "HandlerC passed " << i << " ";
      Handler::handle(i);
    }else{
      cout << "HandlerC handled " << i << " ";
    }
  }
};


int main(){
  srand(time(0));
  ConcreteHandlerA root;
  ConcreteHandlerB b;
  ConcreteHandlerC c;
  root.add(&b);
  root.add(&c);
  c.setNext(&root);
  for(int i=1;i<10;i++){
    root.handle(i);
    cout << "\n";
  }
}