kakke18’s blog

ゆるふわ学生エンジニア

Prototype-コピーしてインスタンスを作る-

Java言語で学ぶデザインパターン入門 の第6章を参考にしました。

つまり、new Hoge();のようにクラス名を指定してインスタンス生成を行うのではなく、 クラス名を指定せずにインスタンスを複製して新しいインスタンスを作るということです。 それは、以下のような場合に使われます。

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

    扱うオブジェクトの種類が多すぎて、1つ1つを別のクラスにするとソースファイルを多数作成する必要が生じる場合

  • クラスからのインスタンス生成が困難

    ユーザの操作によって作成されるインスタンスのように複雑な過程でインスタンスが生成される場合

  • フレームワークをクラスに依存させない

    インスタンスを生成するフレームワークを特定のクラスに依存しないように作る場合

このような場面において、Prototypeパターンは有効であります。 "prototype"には、”原型”という意味があり、 原型となるインスタンスを元に新たなインスタンスを作り出します。 これらを実現するためにJavaのcloneメソッドやCloneableインターフェースを用います。

実装

こちらを参考にしてください。

登場人物

  • Prototype役(Prototypeインターフェース)

    インスタンスを複製して新しいインスタンスを作るためのメソッドを定める

  • ConcretePrototype役(MessageBoxクラス、UnderlinePenクラス)

    Prototypeで定められたメソッドを実装する

  • Client役(Manegerクラス)

    インスタンスをコピーするメソッドを利用して、新しいインスタンスを作る

実装のポイント

  • Productインターフェースのようにjava.util.Cloneableインターフェースを継承させたインターフェースを実装したクラス (ConcretePrototype役)のインスタンスは、 cloneメソッドを用いることで自動的に複製を行うことが可能である。
  • java.util.HashMapを用いて、”名前”と”インスタンス”の関係を表現(Managerクラス)

Prototypeパターンのメリット

なぜnew Hoge();のように素直にインスタンス生成をしないのでしょうか。 それは、前述した通り3つの場合において、クラス名を指定せずにインスタンス生成させるほうが都合が良いからです。

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

今回のサンプルプログラムでは、以下の3つの雛形が登場しました。

  • '~'を使って文字列に下線を引くもの
  • '*'を使って文字列に枠をつけるもの
  • '/'を使って文字列に枠をつけるもの

この例では3つだけでしたが、このようなものは作ろうと思えば大量に作ることができます。 それら全てを別々のクラスにしていては、クラス数が多くなりすぎて管理コストがかかってしまいます。

クラスからのインスタンス生成が困難

今回の例では、実感ができません。

フレームワークをクラスに依存させない

サンプルプログラムでは、インスタンスの複製を行う部分をframeworkパッケージの中に閉じ込めています。 そして、Managerクラスのcreateメソッドによって、クラス名の代わりに文字列をインスタンス生成のための名前として与えています。 つまり、frameworksパッケージの中では、特定のクラス名が使用されていないので、クラスに依存していないことになります。

ここで、「クラス名に依存することは悪いことなのか」という疑問が浮かぶと思います。 ソースの中に利用するクラス名を書くことが常に悪いことではありませんが、 そのソースとクラスは切り離して再利用することが不可能となります。 つまり、オブジェクト指向プログラミングの目標の一つである「部品としての再利用」が困難になってしまいます。

まとめ

Prototypeパターンは、生成するべきインスタンスが大量の場合などインスタンスからインスタンス生成を行いたい場合に有効なデザインパターンである。