Effective java 輪読会 第4章 項目18-22

41
Effective Java 輪輪輪 輪 3 輪輪 18 22 2013/12/18 輪輪輪 輪輪

Transcript of Effective java 輪読会 第4章 項目18-22

Page 1: Effective java 輪読会 第4章 項目18-22

Effective Java 輪読会 第 3回(項目 18 ~ 22 )2013/12/18

開発部 野口

Page 2: Effective java 輪読会 第4章 項目18-22

項目 18抽象クラスよりインタフェースを選ぶ

Page 3: Effective java 輪読会 第4章 項目18-22

抽象クラスとインタフェース 抽象クラス

実装を含むことができる サブクラス化が必要

Java は単一継承のみを許可している インタフェース

実装を含むことができない サブクラスである必要がない

Page 4: Effective java 輪読会 第4章 項目18-22

インタフェースの利点( 1/3 ) 新たに実装することが容易

型階層に影響を及ぼさないため 抽象クラスの場合、型階層に組み入れる必要がある

ミックスインを定義するのに理想的 クラスが「本来の型」に加えて、なんらかの任意

の振る舞いを提供していることを宣言するために、クラスが実装する型 例) Comparable

Page 5: Effective java 輪読会 第4章 項目18-22

インタフェースの利点( 2/3 ) 階層を持たない型フレームワークを構築でき

る 例) pp.91-92 SingerSongwriter

抽象クラスで行うと、組み合わせ爆発が起こる! 安全で強力な機能エンハンスを可能にする

ラッパークラスによって、継承しなくてもエンハンスできる 例)項目 16 InstrumentedSet

Page 6: Effective java 輪読会 第4章 項目18-22

インタフェースの利点( 3/3 ) 抽象骨格実装クラスを提供することで、抽象

クラスの長所も取り入れることができる 例)主要なコレクションインタフェース

具象実装の例 : pp. 92-93 intArrayAsList() 擬似多重継承を用いることもできる

ラッパークラスの応用形

Page 7: Effective java 輪読会 第4章 項目18-22

抽象クラスの利点 発展させるのが容易

たとえば、抽象クラスに具象メソッドを追加するだけで、すべてのサブクラスがそのメソッドを提供することになる インタフェースでは、そうはいかない。追加した時点

でコンパイルエラーになる インタフェースは、凍結前にできるだけ(多くのプロ

グラマが)実装することでテストすべき

Page 8: Effective java 輪読会 第4章 項目18-22

まとめ( 1/2 ) インタフェースは、一般的に複数の実装を許

す型を定義する最善の方法 発展しやすさが、柔軟性と能力よりもより重

要だと考えられている場合は例外 そのような場合は、抽象クラスを使用する

Page 9: Effective java 輪読会 第4章 項目18-22

まとめ( 2/2 ) 重要なインタフェースを提供するときは、骨

格実装の提供を検討しよう public インタフェースは細心の注意を払って

設計し、複数の実装を書くことで徹底的にテストしよう

Page 10: Effective java 輪読会 第4章 項目18-22

項目 19 型を定義するためだけにインタフェースを使用する

Page 11: Effective java 輪読会 第4章 項目18-22

インタフェースの目的 インタフェースを実装するクラスのインスタ

ンスを参照するために使用できる型として機能すること

実装するクラスのクライアントは何ができるかを述べること

他の目的は、不適切

Page 12: Effective java 輪読会 第4章 項目18-22

不適切なインタフェースの例 定数インタフェース

「定数インタフェースパターンは、インタフェースの下手な使い方」 実装の詳細であり、クラスのユーザには何の意味もな

いから (本来は不要な)負うべき義務を表しているから

定数が必要なくなっても、バイナリ互換性のためにそのインタフェースの実装が必要

疑問 : 「バイナリ互換性のため」というのは、どういう意味……?

 →定数インタフェースを implements しているクラスに何かしら影響がある

Page 13: Effective java 輪読会 第4章 項目18-22

定数インタフェースを避ける その定数が結びついたクラスやインタフェー

ス自体に定数を追加する 例) Integer.MIN_VALUE や

Integer.MAX_VALUE 列挙されるものなら、 enum を使用する 定数インタフェースよりは、ユーティリティクラ

スを使用する static インポートを活用すれば、長い修飾をするこ

とも回避できる

Page 14: Effective java 輪読会 第4章 項目18-22

項目 20タグ付クラスよりクラス階層を選ぶ

Page 15: Effective java 輪読会 第4章 項目18-22

タグ付クラス 振る舞いを切り替えるためのタグを( enum

等のかたちで)メンバに持ち、そのメンバの設定値に応じて各種操作に対する振る舞いを switch 文で切り替えるようなクラス 例) pp.98 Figure クラス

Page 16: Effective java 輪読会 第4章 項目18-22

タグ付クラスは、冗長で、誤りやすく、非効率( 1/2 )

enum 宣言、タグフィールド、 switch 文といったお決まりのコードで散らかっている

複数の実装が単一クラスに詰め込まれ、読みづらい

他の特性に属する関係のないフィールドによって、メモリ量が増加する

フィールドを自然に final にできない フィールド初期化の正しさについて、コンパ

イラの助けを得られない

Page 17: Effective java 輪読会 第4章 項目18-22

タグ付クラスは、冗長で、誤りやすく、非効率( 2/2 )

特性の追加に際して、ソースの修正が必要 OCP ( Open-Closed Principle / 開放 -閉鎖の原則)違反!

特性の追加に際して、すべての switch 文へ漏れなく case 追加が必要

型から特性に関する手がかりが得られない

Page 18: Effective java 輪読会 第4章 項目18-22

かわりにクラス階層を選ぼう さっきのデメリット全部解消できます

Page 19: Effective java 輪読会 第4章 項目18-22

タグ付クラスからクラス階層へ変換するためのざっくりした 3 ステップ

抽象クラスを定義する 特性ごとに具象サブクラスを定義する 抽象メソッドを個々の具象サブクラスで実装

する 例) pp.99 Figure / Circle / Rectangle クラ

Page 20: Effective java 輪読会 第4章 項目18-22

See Also:

『リファクタリング』( Martin Fowler ) サブクラスによるタイプコードの置き換え State/Strategy によるタイプコードの置き換え ポリモーフィズムによる条件記述の置き換え

Page 21: Effective java 輪読会 第4章 項目18-22

項目 21 戦略を表現するために関数オブジェクトを使用する

Page 22: Effective java 輪読会 第4章 項目18-22

関数をパラメータ化する様々な機構

関数ポインタ( C とか) デリゲート( C# とか) ラムダ式( Lisp とか)

Page 23: Effective java 輪読会 第4章 項目18-22

関数オブジェクト 他のオブジェクトに対して操作を行うメソッ

ドを 1 つだけ公開するオブジェクト 実質、そのメソッドへのポインタ

Page 24: Effective java 輪読会 第4章 項目18-22

例: StringLengthComparator

文字列比較に対する具象戦略( concrete strategy ) 状態を持たない

よって、シングルトンにするとよい

Page 25: Effective java 輪読会 第4章 項目18-22

戦略インタフェース 戦略を切り替えられるようにするために、具

象戦略が実装するインタフェース 例) Comparator<T>

無名クラスを使用して宣言するのもよい ただし、インスタンス生成コストに注意 名前がつけられないのもデメリットとなりうる

Page 26: Effective java 輪読会 第4章 項目18-22

ホストクラス 具象戦略を private な内部クラスとして、イン

タフェースを通して外部に提供する 例) pp.103 Host クラス

*疑問 : pp.103 の StrLenCmp はなぜ(何のために) Serializable を実装しているのか?(単なる例示のため?だとしたら、あまり良い例ではないような……)→Comparator を Serialize して転送したいこともある!

Page 27: Effective java 輪読会 第4章 項目18-22

まとめ 関数ポインタの主な使用方法は、 Strategy

パターンを実装すること Java での実装は、戦略インタフェースと、そ

れを実装する具象戦略クラス 具象戦略が 1度しか使用されない場合は、無名クラスを使用するとよい

繰り返し利用される場合は、ホストクラスを導入するとよい

Page 28: Effective java 輪読会 第4章 項目18-22

補足( 1/2 ) Java8 ではラムダ式も使えるそうですね!

Before ( pp.102 ) :

Arrays.sort(stringArray, new Comparator<String>() { public int compare(String s1, String s2) { return s1.length() - s2.length(); } });

Page 29: Effective java 輪読会 第4章 項目18-22

補足( 2/2 ) Java8 ではラムダ式も使えるそうですね!

すっきり!

参考 : http://dstn.appresso.com/developer/detail/?id=131 http://d.hatena.ne.jp/nowokay/20130824

After (ラムダ式による記述) :

Arrays.sort(stringArray, (s1, s2) -> s1.length() - s2.length());

Page 30: Effective java 輪読会 第4章 項目18-22

項目 22 非 static のメンバークラスより static のメンバークラスを選ぶ

Page 31: Effective java 輪読会 第4章 項目18-22

ネストしたクラス 他のクラス内に定義されたクラス エンクロージングクラスに対して仕えるためだ

けに存在すべき 他の何らかの状況で有用ならば、トップレベルの

クラスであるべき

Page 32: Effective java 輪読会 第4章 項目18-22

4 種類のネストしたクラス static のメンバークラス 非 static のメンバークラス 無名クラス ローカルクラス

Page 33: Effective java 輪読会 第4章 項目18-22

static のメンバークラス エンクロージングクラスのメンバーのすべてに

アクセスできる public のヘルパークラスとして提供すること

もできる 例) pp. 104 Calculator.Operation

Page 34: Effective java 輪読会 第4章 項目18-22

非 static のメンバークラス メンバークラス生成時に、そのエンクロージン

グインスタンスと関連付けられる 関連付けの際にメモリを消費し、インスタン

スの生成時間が増加する アダプターの実装に用いることができる

例) Map インタフェースのkeySet 、 entrySet 、 values

Page 35: Effective java 輪読会 第4章 項目18-22

非 static のメンバークラスよりstatic のメンバークラスを選ぶ

エンクロージングオブジェクトへの関係のない参照を持たない

ガーベッジコレクションへの悪影響を防ぐ public あるいは protected のメンバーの場

合は、あとから変更できないので特に慎重に選ぶこと

Page 36: Effective java 輪読会 第4章 項目18-22

無名クラス( 1/2 ) 名前を持たない エンクロージングクラスのメンバーではない ( static の文脈内で書かれたとして

も) static のメンバーを持つことはできない 宣言された箇所以外でインスタンス化できな

Page 37: Effective java 輪読会 第4章 項目18-22

無名クラス( 2/2 ) instanceof やクラスの名前を利用できない 複数のインタフェースを実装したりできない クライアントは、スーパータイプから継承され

たメソッド以外呼び出せない 短くあるべき( 10 行以下が目安)

Page 38: Effective java 輪読会 第4章 項目18-22

無名クラスの用途 関数オブジェクトとして使用する

See also: 項目 21 プロセスオブジェクトを生成する

例) Runnable インスタンス、 TimerTask インスタンス等

static ファクトリーメソッド内で使用する 例)項目 18 の intArrayAsList

Page 39: Effective java 輪読会 第4章 項目18-22

ローカルクラス ローカル変数が宣言できる場所すべてで宣言で

きる 無名クラスと同様、 static のメンバーを持て

ない 無名クラスと同様、短くあるべき

Page 40: Effective java 輪読会 第4章 項目18-22

まとめ( 1/2 ) 4 種類のネストしたクラスがあり、それぞれ異

なる用途がある メソッド内に収まらないようなものは、メン

バークラスにする エンクロージングインスタンスへの参照が必要

なら、非 static にする そうでなければ、 static にする

Page 41: Effective java 輪読会 第4章 項目18-22

まとめ( 2/2 ) メソッド内に属しているべきで、 1箇所から

のみ生成され、ベースとなる型が存在するなら、無名クラスにする そうでなければ、ローカルクラスにする