##概要
構造と振る舞いを分離するためのパターン
以下の5種類のクラスからなる
- Visitorクラス(3.に対するVisitオペレーションを宣言する)
- ConcreteVisitorクラス(1.で宣言されたVisitオペレーションを実装する)
- Elementクラス(要素の抽象クラス、visitorを受け取るAcceptオペレーションを宣言する)
- ConcreteElementクラス(要素の具象クラス、3.で宣言されたAcceptオペレーションを実装する)
- ObjectStructureクラス(要素を列挙し、それらに対するオペレーションをvisitorに任せるためのインターフェイスを提供する)
##具体例と実装
訪問販売を例にすると
上記1~5はそれぞれ
- 訪問販売クラス(DoorToDoorSalesmanクラス、訪問のインターフェイスを定義)
- 生命保険販売クラス、健康食品販売クラス(LifeInsuranceDoorToDoorSalesmanクラス、HealthyFoodDoorToDoorSalesmanクラス。訪問販売で各家庭を訪れる)
- 世帯クラス(Householdクラス、訪問販売員を受け入れるインターフェイスを定義)
- 単身世帯クラス、家族世帯クラス(SingleHouseholdクラス、FamilyHouseholdクラス各訪問販売員を受け入れる)
- 販売員派遣元クラス
が対応する。
コードの詳細は以下
door_to_door_salesman.rb
class DoorToDoorSalesman
def visit(household)
end
end
life_insurance_door_to_door_salesman.rb
class LifeInsuranceDoorToDoorSalesman < DoorToDoorSalesman
def visit(household)
household.greet
# 家を訪問
end
end
healthy_food_door_to_door_salesman.rb
class HealthyFoodDoorToDoorSalesman < DoorToDoorSalesman
def visit(household)
household.greet
# 家を訪問
end
end
household.rb
class Household
def accept(door_to_door_salesman)
end
end
single_household.rb
class SingleHousehold < HouseHold
def initialize
end
def accept(door_to_door_salesman)
door_to_door_salesman.visit(self)
end
def greet
puts 'こんにちは'
end
end
family_household.rb
class FamilyHousehold < HouseHold
def initialize
end
def accept(door_to_door_salesman)
door_to_door_salesman.visit(self)
end
def greet
puts 'こんにちは、誰に御用でしょうか??'
end
end
door_to_door_salesman_agency.rb
class DoorToDoorSalesmanAgency
attr_accessor :household_list
def initialize
# 訪問先顧客情報
@household_list = Array.new
end
def add(household)
@household_list << household
end
def remove(household)
@household_list.delete(household)
end
end
client.rb
agency = DoorToDoorSalesmanAgency.new
agency.add(SingleHouseHold.new)
agency.add(FamilyHouseHold.new)
life_insurance_salesman = LifeInsuranceDoorToDoorSalesman.new
healthy_food_salesman = HealthyFoodDoorToDoorSalesman.new
agency.household_list.each do |household|
household.accept(life_insurance_salesman)
household.accept(healthy_food_salesman)
end
##メリット
- 構造とオペレーションが分離されていることによりOCPなコードになり、要素への新しいオペレーションの追加が容易
- オペレーションを実行する要素の型がわからなくとも共通のクラスからオペレーションを呼び出せる
##まとめ
オペレーションを加えるオブジェクトのクラスに変更を加えずに新しいオペレーションを定義することが出来るパターン