Yabu.log

ITなどの雑記

Effective Java item1:Consider static factory methods instead of constructors

サービスプロバイダフレームワークの検証ができていないが、時間をかけすぎているのでこの辺で投稿。*1

コンストラクタだけでなく、static factoryメソッドも検討しましょう。

Boolean temp = new Boolean(true);//コンストラクタ
Boolean temp2 = Boolean.valueOf(true);//スタティックファクトリーメソッド

Static Factoryのメリット

1.名前が持てる

- コンストラクタはクラス名のみ。
- コンストラクタが複数ある場合は引数の意味を注意して覚える必要がある
- 複数のコンストラクタが存在する場合、適切な名前を持つ複数のStatic Factoryメソッドに書き直した方がいい

2.呼ばれるたびにインスタンスを作成しなくてもよい

- 例えば:FlyWeightパターン、Singletonパターン
   - 既存のインスタンスを使い回す柔軟なコーディングが可能。

3.サブクラスのインスタンスを返すことができる

例えば class Dog extends Animalこんなクラスがあるとして

Dogのスーパークラスのstatic factoryメソッドがdogインスタンスを返すことができる。

 Animal animal = Animal.newDog("potchi");
 animal.bark();

4.引数によって返すインスタンスのクラスを変更できる*2

例えばEnumSetクラスのstatic factoryメソッドのnoneofは引数のenumの数が - 64以下ならRegularEnumSetを - 65以上ならJumboEnumSetを返す

ちなみにこれはRegularEnumSet内部でEnumの要素の有無をlong型(64bit)の変数で管理しているからであり、 65以上の要素を持つEnumは扱えないので、代わりに内部でlong型の配列で値を保持するJumboEnumSetを返す。*3

5.戻り値のクラスはstatic factoryメソッド作成時に存在していないくていい

JDBCなどのライブラリの設計の根幹となる考え方らしい。Effective Java第2番にはサービスプロバイダーフレームワークの例が乗っていましたが、 これがごっそり削除されました。ここはJDBCなどをダウンロードしてしっかり検証すべき。*4

とのことだけどどんなのが載ってたんだろう。。。気になる。

デメリット

1.public,protectedのコンストラクタのないクラスははサブクラス化できない

例:コレクションフレームワーク内の便利な実装クラス*5はサブクラス化することができない。

2.適切な名前をつけないと見分けがつかない

コンストラクタはそのままクラス名がメソッド名になるが、スタティックファクトリは実装者が考えて命名する必要がある。以下のような命名が一般的らしい

from

引数の型からファクトリメソッドの型へ変換を行う

以下の例だとDateクラスのファクトリによってInstant -> Dateの変換が行われている

// example of "from"
Instant instant = Instant.now();
Date d = Date.from(instant);

of

複数のパラメータを含んだinstanceを作る

Set<Rank> faceCards = EnumSet.of(Rank.JACK, Rank.QUEEN, Rank.KING);

valueOf

その値をもつオブジェクトを作る

BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);

instance または getInstance

インスタンスが一つしか存在しないインスタンスを返す(シングルトン)

Calendar cal = Calendar.getInstance();

create または newInstance

getInstanceと違って返されるインスタンスはそれぞれ異なっている

Object newArray = Array.newInstance(String.class, 4);

getType

getInstanceに似ている。の唯一のインスタンスを返す。

FileStore fs = Files.getFileStore(path);

Filesクラスは他にも以下のようなgetType系のstatic factoryを保持している

getAttribute(Path, String, LinkOption...) getFileAttributeView(Path, Class, LinkOption...) getLastModifiedTime(Path, LinkOption...) getOwner(Path, LinkOption...) getPosixFilePermissions(Path, LinkOption...)

newType

getTypeと違って呼ばれるたびに返されるインスタンスを生成する

BufferedReader br = Files.newBufferedReader(path);

type

getType,newTypeの代替として使用される

Vector<String> v = new Vector();
v.add("aa");
v.add("bb");
List<String> testList = Collections.list(v.elements());

感想

  • サービスプロバイダフレームワークの箇所は説明が増えているがコード例がごっそり消えている
  • Static factoryを使えばジェネリクスをコンストラクタ、型両方に書く煩わしい記述を省略できる!との指摘は消えていました
Map<String,Integer> test = new HashMap<String,Integer>
Map<String,Integer> test2 = HashMap.newInstance
  • 第2版の日本語役で1.7で追加されたダイアモンド演算子型推論により解決していると指摘されていましたね。

ちなみにGoogle Collectionとして開発が進められていたGuavaですが、

qiita.com

著者のJoshua blochが関わっているためか、Mapクラスにこのsatatic factoryメソッドが実装されています

Map<KeyType, LongishValueType> mapGuava = Maps.newLinkedHashMap();

The library's design and code were advised and reviewed by Joshua Bloch

Google Guava - Wikipedia

Sunでコレクションを一通り作った知見を生かしてGoogleで作り直されたのでしょうか。 なかなか興味深いOSSですね😎

*1:最近はプログラミング環境の整備みたいなのをやりまくってて、トラブルシュートの時間が多すぎてあまり本質的な作業ができていない。JDBC等の導入も週末余裕があるときに進めようと思う。

*2:もちろん宣言クラスかそののサブクラス限定だが

*3:EnumSetを使ったことがないので調査に時間がかかった

*4:Javaで仕事をしたことがないのでこういう実戦寄りのライブラリとかに疎い

*5:ImmutableCollectionsのインナークラスのList1とか。