「機能java」クラスとインタフェースItem 16-共通クラスは、共通フィールドではなくビジターメソッドを使用します.


オブジェクト向けプログラミング:
共同で使う部分を事前に抽象化することです.
コードの再利用性を向上させるために、必要に応じて最適化します.
それがOOPの指向点です.
Javaでは抽象的な基本単位はクラスとインタフェースであり,これはJavaの心臓のようなものである.
「第4章-クラスとインタフェース」には、次の項目があります.
書きやすく、堅牢で柔軟なクラスとインタフェースを作成する方法について説明します.
Item15. クラスとメンバーのアクセス権を最小化します.Item16. publicクラスでは、publicフィールドではなくアクセス者メソッドを使用します.Item17. 変更の可能性を最小限に抑える.Item18. 継承するより複合語を使うほうがいいです.Item19. 継承を考慮して設計し記録する.そうでなければ継承は禁止されます.Item20. インタフェースは抽象クラスより優先されます.Item21. インタフェースは、実施者を考慮して設計される.Item22. インタフェースはタイプを定義するためにのみ使用されます.Item23. ラベル付きクラスではなくクラス階層を使用します.Item24. できるだけメンバークラスを静的にします.Item25. 1つのファイルにはトップクラスが1つしか含まれていません.

<「publicフィールドではなく、publicクラスでアクセス者メソッドを使用します。」>


#   publicクラスの場合


最初は次の例を見てみましょう.
class Point {
  public double x;
  public double y;
}
上記のようにインスタンスフィールドのみが収集される場合があります.
(作者は「退歩的」というドラマチックなwadding...)
私は論理的な有無を言っているわけではありません.
エンティティを定義する場合、通常はフィールドのみを宣言します.
問題はその場所だけの時に起きた.
誰もが公衆として宣言されたので、
このクラスのデータフィールドには、他のコンポーネントから直接アクセスできます.
つまり、カプセル化が全くできないため、それなりのメリットも得られない.
実際、長所を得ることができないというよりは、多くの欠点と危険性がある.
<短所>
  • では、スクリーンショットのメリットはありません.
  • APIを変更しないと、内部表示は変更できません.
  • 不変式は保証できません.
  • からフィールドに外部からアクセスする場合も、副手操作は実行できません.(Thread不安定、Race Condition)
  • したがって、上記のコードは以下のように変更する必要があります.
    class Point {
        private double x;
        private double y;
    
        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    
        public double getX() { 
      		return x; 
      	}
        public double getY() { 
      		return y; 
      	}
    
        public void setX(double x) { 
      		this.x = x; 
      	}
        public void setY(double y) { 
      		this.y = y; 
      	}
    }
    すべてのデータフィールドのアクセス性をprivateに変更します.
    次に、データフィールドにアクセスするための個別の方法を作成します.
    Javaはこれらを訪問者と呼ぶ.
    前述したように、パッケージの外部からアクセス可能なクラスにアクセス者を指定する場合は、次の手順に従います.
    いつでも、階級内部の表現方式を柔軟に変えることができる.
  • ここで、「内部表現」が柔軟になった意味を「変数名」に置き換えると、少し分かりやすくなります.
  • アクセス者を使用してフィールドを直接露出しない場合、クライアントは対応する変数名を使用します.
  • この変数名を変更したい場合は?使用するクライアントはすべて変更されるため、実際には変更は不可能です.
  • ただし、クライアントがアクセス者(Getter,Setter)を使用する場合、内部で変数名を任意に変更できます.
  • #   private-package、privateクラスの場合


    では、クラスがpublicクラス、private-packageクラス、privateネストクラスでなければ?
    この場合、データフィールドが露出するかどうかはあまり関係ありません.
    △どうせ外部から近づくわけにも、修正するわけにもいかない.
    このとき、本分を尽くして、そのクラスが実現したい機能をしっかり実現すればいいのです.
    実際には、クラス宣言においても、クライアントコードにおいても、アクセス者よりもずっときれいです.
    (実際には、直接フィールドを使用するのは、クライアントコードでアクセス者を使用するよりも簡潔です.)
  • という疑問があるかもしれません.
  • 「変数名を変えたらクライアントも変えますよね?」
  • 共通クラスは公開APIであるため、世界中のすべての人がクライアントであるが、package-privateはパッケージ内にのみクライアントが存在する.
  • 仙子は変えることは不可能で、後者は変えることは難しくありません.可能性自体が違う.
  • 重複するprivateクラスは実現しやすい.
    このクラスを使用できるのは外部クラスが1つしかないので、クライアントのオブジェクトになるのはずっと小さいです.
    内部表現は修正しやすい.

    #   共通クラスのフィールドが変わらない場合は?


    変わらなければ、直接露出する欠点は減ります.
    不変式を満たすことができるが、他の欠点があるかどうか.
    内部表示は変更できません.また、フィールドの読み取り時に破壊操作を実行することはできません.
    次の例を見てください.
    public final class Time {
        private static final int HOURS_PER_DAY    = 24;
        private static final int MINUTES_PER_HOUR = 60;
    
        public final int hour;
        public final int minute;
    
        public Time(int hour, int minute) {
            if (hour < 0 || hour >= HOURS_PER_DAY)
                throw new IllegalArgumentException("Hour: " + hour);
            if (minute < 0 || minute >= MINUTES_PER_HOUR)
                throw new IllegalArgumentException("Min: " + minute);
            this.hour = hour;
            this.minute = minute;
        }
    
    }
    入力した時間が有効な時間であることを確認するクラスです.
    筆者のコメントで文章を締めくくる.
    Item 16の定理
  • 共通クラスは、可変フィールドを直接露出することは絶対にできません.
  • 変わらない場所であれば、露出してもそんなに危険ではありませんが、完全に安心することはできません.
  • package-privateまたはオーバーラップprivateクラスは、露出することが望ましい場合がある.