Javaで型トークンを利用したファクトリクラスを書いてみた
はじめに
Javaでインスタンスを生成するクラス、いわゆるファクトリクラスを書く場合、色々な書き方があると思いますが、特定のクラスのインスタンスのみしか作れないとわりと不便なので、今回は、型トークン(クラスクラスと呼ばれるやつですね: Class<T> です)を引数として渡してそのクラスのインスタンスを返却してくれるとファクトリを書いてみました。
さらにそのファクトリを通して一度生成しているインスタンスについては同じものを返してくれるとメモリの節約にもなってよいですね。
というわけで、早速ソースとテストコードです
説明
とりあえず、クラスがないと説明しにくいのでテスト用に以下のような階層のクラスを作ってあります。
Alphabet <-- 抽象クラス |- A <-- 具象クラスその1 |- B <-- 具象クラスその2 +- C <-- 具象クラスその3
さて、ここで、Aのインスタンスを取得するためのファクトリの使い方は以下のようになります。
// Alphabetのサブクラス用のファクトリ Factory<Alphabet> factory = new Factory<Alphabet>(); // Aのインスタンスを取得 A a = factory.getOrCreate(A.class);
#getOrCreateメソッドに型トークン(Class<A>)を渡すことにより、Aのインスタンスを取得できています。ファクトリ内部では、型トークンをキーとしたマップにインスタンスが保持されているため、再度 #getOrCreate(A.class) を呼び出した場合は同じインスタンスが取得されます。
A a1 = factory.getOrCreate(A.class); A a2 = factory.getOrCreate(A.class); a1 == a2; // => true: 同じインスタンス
もちろん、型トークンを変えれば違う型のインスタンスも取得できます。
B b = factory.getOrCreate(B.class); C c = factory.getOrCreate(C.class);
ただし、Factory<T>はジェネリックなクラスとし、Tという型パラメータで指定されたクラスのサブクラスのみ生成可能となるよう制限をかけています。
#getOrCreateメソッドもジェネリックになっており、型パラメータUは<U extends T>としてありますので、Tのサブクラスの型トークンのみを引数として取れる、という風になっています。
public <U extends T> U getOrCreate(Class<U> clazz) { ... }
蛇足
昔、Java1.4の頃、これと同様のことをやりたくて、ファクトリクラスには生成する必要があるクラス分だけ、getterメソッドを作った記憶があります…今となってはいい思い出です。
class Factory14 { Foo createFoo() { ... } Bar createBar() { ... } Baz createBaz() { ... } . . . }
参考書籍
Effective Java 第2版 (The Java Series)
- 作者: Joshua Bloch,柴田芳樹
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2008/11/27
- メディア: 単行本(ソフトカバー)
- 購入: 57人 クリック: 745回
- この商品を含むブログ (247件) を見る
主に第5章:ジェネリックスと項目29を参照