1つずつデザインパターンをまとめ
総論
パターンそのものと使い所を理解する
Factory Method(ファクトリーメソッド)パターン
セットとなる(製品)オブジェクトを容易に生成してくれるパターン。
ある作成者オブジェクトを選択することが、製品オブジェクトの「クラスの選択」をも決定づけるパターン。
Factory Methodのテンプレート
SuperProduct.rb
class SuperProduct
def initialize(product)
@product = product
end
def template_method()
abstract_method()
end
def abstract_method()
raise 'Abstract method'
end
end
SubProduct1.rb
require './SuperProduct'
class SubProduct1 < SuperProduct
def initialize(product1)
super
end
def abstract_method()
puts "#{@product}の特徴1"
end
end
SubProduct2.rb
require './SuperProduct'
class SubProduct2 < SuperProduct
def initialize(product2)
super
end
def abstract_method()
puts "#{@product}の特徴2"
end
end
SuperCreator.rb
require './SubProduct1'
require './SubProduct2'
class SuperCreator
def initialize(args)
@product1 = new_product(:type1, args[:name1])
@product2 = new_product(:type2, args[:name2])
end
def factory_method()
@product1.template_method()
@product2.template_method()
end
def new_product(type name)
return SubProduct1.new(name) if type == :type1
return SubProduct2.new(name) if type == :type2
raise "Unknown product type #{type}"
end
end
Main.rb
require './SuperCreator'
class Main
creator = SuperCreator.new(:name1 => '製品1', :name2 => '製品2')
creator.factory_method()
end
使い所
〇〇と△△に適した□□を作り、××したい
例) アヒルとスイレンに適した池を作り、1日の生体観察をしたい
- 製品が「アヒル」、「スイレン」(サブクラス)
- 作成者が「池」(スーパークラス)
- 池クラスの生成時に、作るべきオブジェクトの型を知らせるパラメータを渡す。(new_product()が呼び出され、製品クラスの型が決定。)
- 「1日をシュミレーションする」時に行う基本ステップを抽象メソッド(abstract_method())として定義し、テンプレートメソッドで呼び出すようにする
- 動物が鳴く
- 動物が食事をする..
- 植物が成長をするetc..
- 「(池の)1日をシュミレーションする」メソッド(ファクトリーメソッド)を実行
- アヒルやスイレンが、それぞれの1日の活動を行う
特徴
- ファクトリーメソッド = テンプレートメソッド
- 新しいオブジェクトの作成の問題に適用しただけ
- オーソドックスなFactory methodの問題は、パターンが作るオブジェクトの型ごとに別々のサブクラスを必要とすること(追加したい製品オブジェクトが増えていくと、作成者オブジェクトのサブクラスも組み合わせだけ倍々ゲームのごとく作ることになる)
- なので上記の例はその欠点を補ったパラメータ化されたファクトリーメソッド
考え方
- このパターンの「作成者」、「製品」とはオブジェクトの関係性を表す表現
- 「作成者」オブジェクトが、「製品」オブジェクトを作るという動きのため(「作成者」の生成と同時に「製品」が決まる)
- オーソドックスなFactory methodはサブクラスの「作成者」オブジェクトを生成する
- 製品化させたいオブジェクトが1、2個なら問題ないが、それ以上なら実用的とはいえなそう
手順
- 必要な製品オブジェクトを検討しクラスを作成
- 共通な性質をもつ製品オブジェクトがあるか検討しスーパークラスを作成してテンプレートメソッドを実装
- 製品オブジェクトを呼び出す作成者クラスを作成
- 製品オブジェクトを呼び出す組み合わせが2つ以上ある場合はファクトリーメソッドを実装し、組み合わせの1つを実現するサブクラスの作成者クラスを作成
- 製品オブジェクトを呼び出す組み合わせが2 ~ 4程ある場合は製品オブジェクトを作成者のスーパクラスにパラメータで渡す方法にし、サブクラスを削除
- 作成者クラスを生成し、ファクトリーメソッドを実行
ポイント
- 製品オブジェクトを呼び出す組み合わせが最初から5以上くらい or 今後も増え得るのであればAbstract Factoryを使った方が適切
- アジャイル的に進めるのであればFactory Method -> Abstract Factoryと段階的に利用するのが良さそう
- 全てのオブジェクトをファクトリから生成する必要があるわけではない(はず)
書籍情報
Russ Olsen, Rubyによるデザインパターン
https://amzn.to/2PFKt6m
雑感
この本の随所にYAGNI原則を出してくる理由が分かる。デザインパターンを知るとすげーと思うのと同時につい使いたくなる。なにに効果が高いのかをしっかり考えて使う