趣旨
駆け出しエンジニアの備忘録の垂れ流し。
※ 出典漏れがあればご指摘ください
出典:
https://yamakatsusan.web.fc2.com/
https://dackdive.hateblo.jp/
https://www.oreilly.co.jp/books/9784873117393/
builderパターン概要
複合オブジェクトについて,その作成過程を表現形式に依存しないものにすることにより,同じ作成過程で異なる表現形式のオブジェクトを生成できるようにする。
Builderでは複合オブジェクトを段階的に作成していく過程に焦点をあてる。Abstract Factoryでは部品の集合を強調している(それが単純であっても複雑であっても)
- 複雑な部品生成処理を行う場合、作成を指示するdirectorを設けることで、clientと作成者(builder)との間に必要な、複雑な処理を吸収する。directorのメインルーチンで生成手順を記述するため、builderに段階的に部品を作らせることも、複数の部品を作らせることも可能。
- 段階的な手順での部品作成が必要であり、かつ、部品の作成手順が頻繁に変更される可能性が存在する場合に利用する
クラス図とシーケンス図
wikipediaより引用
実装方針
- AbstractBuilderクラスではtemplate methodのようにオブジェクトインスタンス作成手順(必須メソッド)を規定する。
- Builderサブクラスでは必須メソッドをオーバーライドする。
- Directorクラスでは生成処理(construct)としてbuilderの必須メソッドを呼び出しながら、オブジェクト生成の手順を記述する。
- Client側ではDirectorクラスのみ呼び出し、directorのconstructのみを呼び出すことでオブジェクトを生成する処理を記述する。
実装例1
# builder側
class AbstractBuilder:
@abstractmethod
def build_part1(self):
pass
@abstractmethod
def build_part2(self):
pass
@abstractmethod
def build_part3(self):
pass
class ConcreteBuilder(AbstractBuilder):
def build_part1(self):
# 実処理を記載
self.do_something() # 処理を実装
def build_part2(self):
# 実処理を記載
self.do_something2() # 処理を実装
def build_part3(self):
return self.get_product() # 処理を実装
# director側
class MyDirector: # 注目すべきは考え方なので、内部の実装は作成するものによる(あくまで一例)
def construct(self):
#生成手順を実装
self.builder.build_part1()
self.builder.build_part2()
return self. builder.build_part3()
@classmethod
def create_director(cls, some_args: obj):
builder_cls = get_builder_cls(some_args) # 処理を実装
return cls(builder_cls())
# client側
def main():
director = MyDirector.create_director("some_args_for_deciding_builder_cls")
product = director.construct()
実装例2_Directorを呼びわけるパターン例
# director側
class AbstractDirector:
@abstractmethod
def construct(self):
pass
@abstractmethod
def create_director(self):
raise NotImplementedError()
@classmethod
def get_director_cls(cls, some_args: obj):
director_cls = get_director_cls(some_args) # 処理を実装
return director_cls
class MyDirector(AbstractDirector):
def construct():
#生成手順を実装
self.builder.build_part1()
self.builder.build_part2()
return self. builder.build_part3()
@classmethod
def create_director(cls,some_args: obj):
builder_cls = get_builder_cls(some_args) # 処理を実装
return cls(builder_cls())
class YourDirector(AbstractDirector):
def construct():
#生成手順を実装
self.builder.build_ex_part1()
self.builder.build_ex_part2()
return self.builder.build_ex_part3()
@classmethod
def create_director(cls,some_args: obj):
builder_cls = get_builder_cls(some_args) # 処理を実装
return cls(builder_cls())
# client側
def main():
director_cls = AbstractDirector.get_director_cls("some_args_1")
director = director_cls.create_director("some_args_2")
product = director.construct()
メリットと使い所
- メリット
- インスタンス生成のロジックが、clientコードに依存しない(Directorのインターフェースに依存する)。
- 複雑な生成処理をDirectorに依存させる事ができる。また用法2のようにDirectorサブクラスでの実装とすれば、
同様のオブジェクトを、異なった手順で生成することもclientに依存させずに作成することができる
- 使い所
- 多くの構成要素からなるオブジェクトを生成するアルゴリズムを,構成要素自体やそれらがどのように組み合わされるのかということから独立にしておきたい場合。
-
オブジェクトの作成プロセスが,オブジェクトに対する多様な表現を認めるようにしておかなければならない場合。
-
段階的な手順での部品作成が必要であり、かつ、部品の作成手順が頻繁に変更される可能性が存在する場合に利用する