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
第2版にあったサービスプロバイダフレームワークのコード例(項目1)が、第3版のレビュー版では分かり易いコード例に変更されていたのですが、最終版ではコード例が全部削除され、文章だけの説明となっていました。|『Effective Java Third Edition』 https://t.co/JW4AxHh0Rb
— Yoshiki Shibata/柴田芳樹 (@yoshiki_shibata) 2018年1月3日
とのことだけどどんなのが載ってたんだろう。。。気になる。
デメリット
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
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
ちなみにGoogle Collectionとして開発が進められていたGuavaですが、
著者のJoshua blochが関わっているためか、Mapクラスにこのsatatic factoryメソッドが実装されています
Map<KeyType, LongishValueType> mapGuava = Maps.newLinkedHashMap();
The library's design and code were advised and reviewed by Joshua Bloch
Sunでコレクションを一通り作った知見を生かしてGoogleで作り直されたのでしょうか。 なかなか興味深いOSSですね😎