[パーフェクトjava]アイテム19継承を考慮して設計し記録する.そうでなければ継承は禁止されます

5612 ワード

ドキュメント化


メソッドを再定義する場合は、何が起こったかを記録します.
継承クラスは、内部で再定義可能なメソッドをどのように使用するか(自己使用)についてのドキュメントを保持します.
開示された方法でクラスの別の方法を呼び出すこともできる.ただし、他のメソッドが再定義可能なメソッドである場合は、そのメソッドを呼び出すAPIの説明に明記する必要があります.
APIドキュメントのメソッドの説明の後に、内部操作を説明する「実装要件」の先頭にあるセクションがあります.
良いAPIは「何をするか」ではなく「どうするか」を説明しなければならない.

保護された製品


内部メカニズムの記録に加えて、クラスの内部動作プロセスの間に挿入される可能性のあるhook(hook)をフィルタリングし、保護された方法で公開する必要がある場合がある.

ListインプリメンテーションのエンドユーザはremoveRangeメソッドに興味がない.しかしながら、一部のリストのclearメソッドをサブクラスでより容易に高性能にするために保護が提供される.
各保護された部分は内部実施に属するため、露出が少なすぎることによる継承利益を避けるために、できるだけ少なく調整しなければならない.
継承クラスをテストする方法「一意」は、サブクラスを直接作成することです.
また、継承のために設計されたクラスは、導入前にサブクラスを作成して検証する必要があります.

その他の制限


継承を許可するクラスには、守らなければならない制約がいくつかあります.
継承クラスの作成者は、再定義可能なメソッドを直接または間接的に呼び出すことはできません.
親クラスの作成者は、子クラスの作成者よりも先に実行されるため、子クラスで再定義する方法は、子クラスの作成者よりも前に呼び出されます.この場合,再定義の方法がサブクラスの新しい聖子で初期化された値に依存する場合,予想通りには動作しない.
public class Super {
    // 잘못된 예 - 생성자가 재정의 가능 메서드를 호출한다.
    public Super() {
        overrideMe();
    }
    
    public void overrideMe() {
    }
}
public final class Sub extends Super {
    // 초기화되지 않은 final 필드, 생성자에서 초기화한다.
    private final Instant instant;
    
    Sub() {
        instant = Instant.now();
    }

    // 재정의 가능 메서드. 상위 클래스의 생성자가 호출한다.
    @Override
    public void overrideMe() {
        System.out.println(instant);
    }
    
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.overrideMe();
    }
}
このプログラムはinstantを2回出力せず、最初の出力nullです.親クラスの作成者は、子クラスの作成者がインスタンスフィールドを初期化する前にoverrideMeを呼び出すためです.CloneableおよびSerializableインタフェースの1つであっても、通常、設計継承実装のクラスには適していない.
直接的であれ間接的であれ、cloneとreadObjectは再定義可能なメソッドを呼び出すべきではありません.

一般クラス


一般的な特定のクラスはfinalではなく、継承やドキュメント化のために設計されていません.しかし,放っておくと,クラスが変化するたびにサブクラスに誤りが生じる可能性がある.
したがって、継承に設計されていないクラスでは、継承を禁止することが望ましい.
クラスはfinalではなくabstractです
継承を禁止する方法は2つあります.
最終宣言
  • クラス
  • は、すべての生成者がプライベートまたはpackage-privateであることを宣言する.
  • スタティックファクトリの使用
    もちろん,具体的なクラスでは標準インタフェースが実装されておらず,継承が禁止されていると使いにくい.継承を許可する場合は、クラス内で再定義可能なメソッドを無効にし、ドキュメントとして保持する必要があります.これにより、再定義メソッドは他のメソッドの動作に影響しません.