yynsmk's tech blog

何でもできる=何にもできない

Prototypeパターンのメリットや使いどころは?

Java言語で学ぶデザインパターン入門を読んでいて詰まった点があったが、いろいろ調べたら腑に落ちたのでメモ。

何が分からなかったのかというと、第6章で登場するPrototypeパターンの使い所についてである。
Prototypeパターン自体は説明やサンプルコードを読めば理解できるのだが、このパターンが実際どういう場面で使われるのかがさっぱりだった。
一応Prototypeパターンについて説明しておくと、プロトタイプとして生成しておいたインスタンスをコピーして新たなインスタンスを生成するデザインパターンである。

Prototypeパターンの使い所

書籍の中では、Prototypeパターンの使い所として以下の3つが挙げられている。

  1. 種類が多すぎて、クラスにまとめられない場合
  2. クラスからのインスタンス生成が難しい場合
  3. フレームワークと生成するインスタンスを分けたい場合

それぞれどういうことを言っているのか順に見ていく。

以下のサイトの説明が分かりやすかった。
6. Prototype パターン | TECHSCORE(テックスコア)
Prototype

種類が多すぎて、クラスにまとめられない場合

まず一つ目。
これが一番の謎だった。
teratailとかの質問にもあったように、
「Prototypeパターンはあるクラスのインスタンスをコピーするだけだから、 似ているが異なるクラスを生成する代わりになんてなれんの?」
「若干のフィールドの違いであればコンストラクタの引数で対応できるくね?」と思った。

しかし、これは処理の重さを考えると、比較的容易に理解できた。

Prototypeパターンを使わなければ、フィールドの値が少し違うだけのクラスがたくさん作られてしまう。
または、1個のクラスにまとめて、コンストラクタの引数にフィールドの値を渡すかだ。
どちらにおいてもフィールドの値が少し違うだけのインスタンスを新たに生成する場合は、コンストラクタを使ってnewする必要がある。
これは、コンストラクタ内の処理が軽ければ、それほど問題がないように思える。
しかし、処理が非常に重く時間がかかる場合に、必要な種類分すべてnewしてインスタンスを生成するのは面倒である。

そういう時に、プロトタイプとなるインスタンスを登録しておけば、コピーしていろんなインスタンスを作れるし、クラス数も減らせるので便利だなと思った。

クラスからのインスタンス生成が難しい場合

これは比較的イメージしやすい。
グラフィックや図形をコピーしたいときに使う。
例えば、ゲームに複数個の同じ爆弾を登場させる時や、パワポの図形をコピーするときなどに使われているみたい。

ユーザのマウス操作を通して作成された複雑な図形やグラフィックをプログラム上でコンストラクタを使って再現するのは面倒そうだし、重たい処理をしなければいけないのが想像できる。
そこでPrototypeパターンを使うと、2回目以降のインスタンス生成が非常に低コストで行える。

フレームワークと生成するインスタンスを分けたい場合

これは使い所というかメリットに近い。
また、Factory Methodパターンと被るところも多い。

Prototypeパターンのクラス図は以下のようになる。(Wikipediaより引用)

f:id:b_murabito:20190530161910p:plain

Prototypeパターンではコピー対象のクラスは必ず、Prototypeになるためのインタフェースを実装しているので、Client側ではインスタンスをコピーする際に具体的なクラス名について知っておく必要がない。
つまり、フレームワーク側が具体的なクラス名に束縛されないということである。

余談:浅いコピーと深いコピー

Prototypeパターンで重要になるのが、コピーが深いかどうかであるが、浅いコピーと深いコピーに関してはこちらが分かりやすかった。
単にclone()するとプリミティブ型のデータは実体がコピーされるが、参照型のデータは実体への参照がコピーされるだけで、浅いコピーとなってしまう。
コピー元のフィードの型に気をつけなれけばならない。