Effective Java 第 2 版:第 4 章 項目 16, 17

項目 16: 継承よりコンポジションを選ぶ

継承を避けておきたい理由

あるサブクラスはスーパークラスの実装に依存してしまうため。 スーパークラスの実装が変わったら、サブクラスの実装も追随して書き換えなければならない。

解決法:コンポジション

コンポジションとは、あるクラスを継承する代わりに、そのクラスを private のフィールドとして持たせたクラスを作ることである。 新たなクラスのメソッド内では、保持しているクラスの対応するメソッドを利用しつつ(転送)、新たな処理も加える。

項目 17: 継承のために設計および文書化する、でなければ継承を禁止する

項目 16 でも述べられていたように、サブクラスはスーパークラスの実装に依存する。 スーパークラスではオーバーライドできるメソッドについて、そのクラス自身がどう利用しているかをドキュメント化しておく必要がある。 protected でメソッドを提供する必要があるかもしれない

継承可能なクラスをテストするためには、2, 3 個のサブクラスを書いてみるしかない。

コンストラクタ内でオーバーライド可能なメソッドを利用してはならない。 なぜなら、スーパークラスのコンストラクタ内でオーバーライドされているメソッドを呼び出すと、サブクラスのメソッドが呼び出されるからである。 サブクラスのコンストラクタは、スーパークラスのコンストラクタのあとに呼び出される。 よって、サブクラスのメソッドがサブクラスのコンストラクタでの処理に依存していると、うまくいかなくなる。 これは、clone, readObject のようなオブジェクトを生成するメソッドにおいても同様である。

サブクラス化したいなら安全な設計をする必要がある。 継承禁止するならクラス宣言に final を付けるか、static ファクトリーメソッドを実装する。

参考文献

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)