概要
GoFのデザインパターンのChainOfResponsibilityパターンについて。
処理の責務をたらい回しにする。
利点としては
・要求側は処理を呼び出す最初の相手だけ知っていれば良い
・処理の連鎖の修正が容易
・各自の処理に専念できる
欠点としては
・遅いこと
登場人物
Handler = 抽象取扱者
ConcreteHandler = 具象取扱者
Client = 利用者
実装サンプル
サンプル概要
Javaのクラスを自動生成したいとします。
利用者がクラス名を渡すと、コードジェネレーターはクラスの名前を元に
処理対象を取り扱う取扱者を判断して責務をたらい回しにします。
取扱担当者が見つかれば該当者がコードの生成を行い結果を返却します。
ここでは条件として以下の優先順で取扱者を判断します。
・Testで始まるクラスはテスト
・Abstractで始まるクラスは抽象クラス
・それ以外は通常のクラス
とすること。
登場人物
取扱者の管理 = ClassGenerateHandlerManager:取扱者の取扱順を管理するクラス
Handler = ClassGenerateHandler:抽象取扱者
ConcreteHandler = TestClassGenerateHandler:具象取扱者
ConcreteHandler = AbstractGenerateClassHandler:具象取扱者
ConcreteHandler = NormalClassGenerateHandler:具象取扱者
Client = main:利用者
サンプルコード
ClassGenerateHandlerManager
# encoding: Shift_JIS require_relative './class_generate_handler' require_relative './normal_class_generate_handler' require_relative './test_class_generate_handler' require_relative './abstract_class_generate_handler' =begin rdoc = ClassGenerateHandlerManagerクラス =end class ClassGenerateHandlerManager attr_accessor :class_generater_handler def initialize() test_class_generate_handler = TestClassGenerateHandler.new abstract_class_generate_handler = AbstractClassGenerateHandler.new test_class_generate_handler.next=abstract_class_generate_handler normal_class_generate_handler = NormalClassGenerateHandler.new abstract_class_generate_handler.next = normal_class_generate_handler @class_generater_handler = test_class_generate_handler end def generate(class_name) return @class_generater_handler.generate class_name end end
ClassGenerateHandler
# encoding: Shift_JIS =begin rdoc = ClassGenerateHandlerクラス =end class ClassGenerateHandler attr_accessor :next NOT_OVERRRIDE = 'not override error' def generate(class_name) if is_target class_name return done class_name else return @next.generate class_name unless @next.nil? end end def is_target(class_name) raise WebPage::NOT_OVERRRIDE end def done(class_name) raise WebPage::NOT_OVERRRIDE end end
TestClassGenerateHandler
# encoding: Shift_JIS require_relative './class_generate_handler' =begin rdoc = TestClassGenerateHandlerクラス =end class TestClassGenerateHandler < ClassGenerateHandler def is_target(class_name) return true unless class_name.scan(/^Test*/).size == 0 return false end def done(class_name) code =<<"EOS" public class #{class_name}() extends TestCase { setUp() { } tearDown() { } } EOS return code end end
AbstractGenerateClassHandler
# encoding: Shift_JIS require_relative './class_generate_handler' =begin rdoc = AbstractClassGenerateHandlerクラス =end class AbstractClassGenerateHandler < ClassGenerateHandler def is_target(class_name) return true unless class_name.scan(/^Abstract*/).size == 0 return false end def done(class_name) code =<<"EOS" public abstract class #{class_name}() { } EOS return code end end
NormalClassGenerateHandler
# encoding: Shift_JIS require_relative './class_generate_handler' =begin rdoc = NormalClassGenerateHandlerクラス =end class NormalClassGenerateHandler < ClassGenerateHandler def is_target(class_name) return true end def done(class_name) code =<<"EOS" public class #{class_name}() { } EOS return code end end
main
# encoding: Shift_JIS require_relative './class_generate_handler_manager' generate_handler_manager = ClassGenerateHandlerManager.new class_name = "TestClass" puts "■#{class_name}を指定" puts generate_handler_manager.generate class_name class_name = "AbstractTestClass" puts "■#{class_name}を指定" puts generate_handler_manager.generate class_name class_name = "NotAbstractTestClass" puts "■#{class_name}を指定" puts generate_handler_manager.generate class_name
出力
■TestClassを指定 public class TestClass() extends TestCase { setUp() { } tearDown() { } } ■AbstractTestClassを指定 public abstract class AbstractTestClass() { } ■NotAbstractTestClassを指定 public class NotAbstractTestClass() { }