Effective Java-クラスとインタフェース(1):クラスとメンバーのアクセス権の最小化

6631 ワード

クラスとメンバーのアクセス権の最小化
良好に実装されるコンポーネントの条件は、すべての内部実装を完全に非表示にし、APIと完全に分離することである.すなわち,内部操作方式を考慮せずにAPIのみを用いて通信を行う.これが캡슐화の概念です.캡슐화の利点は次のとおりです.
  • 以上のコンポーネントを並列に開発し、システム開発の速度を速める.
  • は、各コンポーネントをより迅速に理解し、デバッグし、コンポーネントの交換コストを低減し、システム管理コストを低減することができる.
  • のパフォーマンスの最適化を支援します.
  • ソフトウェアの再利用性を向上させます.独立性のあるコンポーネントは、見知らぬ環境でも役立ちます.
  • システム全体が完了していなくても、単一の素子の動作を検証することができ、大きなシステムの作成の難易度を低減することができる.
  • Javaは、多くの非表示情報を提供するデバイスを提供します.アクセス制御メカニズムは、クラス、インタフェース、およびメンバーのアクセス性(アクセス可能な範囲)を示します.各要素のアクセス性は、アクセス制限者(private、protected、public)として定義されます.コアは、すべてのクラスとメンバーのアクセス性がアクセス制限者を利用してできるだけ縮小しなければならないことです.すなわち、ソフトウェアが正常に動作している限り、常に最小限のアクセスレベルを付与する必要があります.
    トップクラスとインタフェースを付与できるアクセスレベルはpackage-privateとpublicの2種類があります.トップクラスクラスまたはインタフェースがpubliとして宣言されている場合は、公開APIです.package-privateとして宣言されている場合は、パッケージでのみ使用できます.package-privateを使用すると、APIの内部実装ではなく、いつでも変更できます.クライアントにダメージを与えることなく、次のバージョンで変更、置換、削除できます.ただし、publicと宣言されるとAPIになるため、下位互換性を実現するために常に管理されます.
    package-privateで宣言された上位クラスまたはインタフェースを使用するクラスが1つしかない場合は、その上位クラスをユーザークラスのprivate staticクラスにネストします.これにより、パッケージ全体ではなく、クラスにアクセスできるのは1つだけです.
    メンバー(フィールド、メソッド、ネストされたクラス、ネストされたインタフェース)へのアクセス・レベルの付与
  • private:宣言メンバーの上位クラスにのみアクセスできます.
  • package-private:メンバーは、所属するパッケージ内のすべてのクラスからアクセスできます.defaultアクセスレベル.(ただし、インタフェースのメンバーはpublic、デフォルトはdefault)
  • protected:package-privateのアクセス範囲を含むか、メンバーを宣言するクラスのサブクラスからアクセスすることもできます.
  • 公共:どこからでも近づくことができます.
  • 公開APIを詳細に設計した後、他のすべてのメンバーをプライベート化する
  • 以降、package-privateを使用して解凍するには、同じパッケージの他のクラスにアクセスする必要があるメンバーのみが使用できます.
  • が権限を解放すると同時に、システムがコンポーネントをさらに分解する必要があるかどうかを考慮します.
  • privateとpackage-privateメンバーはクラスの実装に相当するため、公開APIには影響しません.しかし,シリアル化が実現されたクラスでは,これらのフィールドが無意識に公開APIになる可能性もある.
    publicクラスで、メンバーのアクセスレベルをpackage-private->protectedに変更すると、アクセス可能なターゲット範囲が大きくなります.publicクラスの保護メンバーは公開APIなので、いつまでもサポートします.また,内部操作方式をAPIに書き込み,ユーザに公開する.だから保護されたメンバーが少なければ少ないほどいいです
    げんかいてん
    常にメンバーの近接性を縮小できるわけではありません.親のメソッドを再定義する場合は、そのアクセスレベルを親のより小さいレベルに設定することはできません.これは、リスク交換の原則は、親のインスタンスがクラスのインスタンスに置き換えられて使用される必要があるからである.違反するとコンパイルエラーが発生します.クラス実装インタフェースは、このルールの特別な例と見なすことができます.この場合、クラスはインタフェース定義のすべてのメソッドを共通として宣言する必要があります.
    テスト時に、クラス、インタフェース、メンバーのアクセス範囲を拡大しようとする場合があります.たとえば、クラス内のプライベートメンバーをpackage-privateに解凍できますが、この値を超えることはできません.適当な程度しかできない.すなわち,テストのためだけに公開APIを使用することはできない.
    publicクラスのインスタンスフィールドはpublicではありません.
    フィールドが可変オブジェクトを参照するか、finalではなくインスタンスフィールドを「共通」と宣言すると、フィールドに含まれる値を制限する能力が失われます.つまり、勝手に外部に変えられるということです.また、フィールドは変更時(例えばrockの取得)に他の操作を実行できないため、public可変フィールドを持つクラスはスレッドセキュリティを持たない.フィールドはfinalで、参照が変更されていないオブジェクトでも同じです.内部実装を変更しようとしても、publicフィールドを消去することで再パッケージすることはできません.
    これは静的フィールドでも同様ですが、例外があります.クラスが表す抽象概念を完成させるために必要なコンポーネント定数であれば、public static finalとして開示することができる.慣例に従って、大文字の変数名で単語間に下線("")を付けます.これらのフィールドは、デフォルトのタイプ値または不変のオブジェクトを参照する必要があります.可変オブジェクトを参照すると、フィールドに適用された変更はすべて同期されます.
    ゼロ以外の長さの配列は変更できます.クラスにpublic static final配列フィールドまたはそのフィールドを返すアクセス者メソッドはありません.
    public static final Thing[] VALUES = {...}; // 보안 허점
    上記の場合は誰でもアクセスできるので、配列の内容を変更できます.
    IDEによって作成されたアクセス者によっては、プライベート配列フィールドの参照が返され、同じ問題が発生することに注意してください.?
    解決策は以下の通り.
  • の共通配列をプライベートに設定し、共通不変リストを追加します.
  • 配列をプライベートに設定し、レプリカを返す共通のメソッドを追加します.
  • // 첫 번째 방법
    private static final Thing[] PRIVATE_VALUES = {...};
    public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
    // 두 번째 방법
    private static final Thing[] PRIVATE_VALUES = {...};
    public static final Thins[] values() { return PRIVATE_VALUES.clone(); }
    お客様が何を望んでいるかによって使用することができます.
    Java 9モジュールの後続技術が必要です