サーチ…


前書き

かなり重要な変数を持つクラスがあり、コードから他のプログラマが設定した値が許容できない値になったとします。これらのコードはコードにエラーをもたらしました。解決策として、OOPでは、(変数に格納されている)オブジェクトの状態をメソッドを通じてのみ変更することができます。オブジェクトの状態を隠し、オブジェクトメソッドを通じてすべての相互作用を提供することは、データカプセル化として知られています。

備考

変数をprivateマーキングし、必要に応じてpublicすることは、すでにpublic変数を隠すことよりもはるかに簡単です。

カプセル化が有益でないかもしれない1つの例外があります: "ダム"データ構造(変数を保持することを唯一の目的とするクラス)

public class DumbData {
    public String name;
    public int timeStamp;
    public int value;
}

この場合は、クラスのインターフェイスは、それが保持するデータです

finalとマークされた変数は、設定後に変更できないため、カプセル化に違反することなくpublicとマークすることができます。

不変量を維持するためのカプセル化

クラスには、インターフェイスと実装の2つの部分があります。

インタフェースは、クラスの公開された機能です。そのパブリックメソッドと変数は、インターフェイスの一部です。

実装は、クラスの内部動作です。他のクラスは、クラスの実装について知る必要はありません。

カプセル化とは、そのクラスの任意のユーザーからのクラスの実装を隠す習慣を指します。これにより、クラスは内部状態についての仮定を行うことができます。

たとえば、Angleを表すこのクラスを取得します。

public class Angle {
    
    private double angleInDegrees;
    private double angleInRadians;
    
    public static Angle angleFromDegrees(double degrees){
        Angle a = new Angle();
        a.angleInDegrees = degrees;
        a.angleInRadians = Math.PI*degrees/180;
        return a;
    }
    
    public static Angle angleFromRadians(double radians){
        Angle a = new Angle();
        a.angleInRadians = radians;
        a.angleInDegrees = radians*180/Math.PI;
        return a;
    }
    
    public double getDegrees(){
        return angleInDegrees;
    }
    
    public double getRadians(){
        return angleInRadians;
    }
    
    public void setDegrees(double degrees){
        this.angleInDegrees = degrees;
        this.angleInRadians = Math.PI*degrees/180;
    }
    
    public void setRadians(double radians){
        this.angleInRadians = radians;
        this.angleInDegrees = radians*180/Math.PI;
    }
    private Angle(){}
}

このクラスは基本的な仮定(または不変式 )に依存します: angleInDegreesとangleInRadiansは常に同期しています。クラスのメンバーが公開されている場合、角度の2つの表現が相関しているという保証はありません。

カップリングを低減するカプセル化

カプセル化を使用すると、クラスを呼び出すコードに影響を与えることなく、クラスを内部的に変更することができます。これにより、 カップリングや、あるクラスが別のクラスの実装にどれくらい依存しているかが減少します。

例えば、Angleクラスの実装を前の例から変更しましょう:

public class Angle {
    
    private double angleInDegrees;
    
    public static Angle angleFromDegrees(double degrees){
        Angle a = new Angle();
        a.angleInDegrees = degrees;
        return a;
    }
    
    public static Angle angleFromRadians(double radians){
        Angle a = new Angle();
        a.angleInDegrees = radians*180/Math.PI;
        return a;
    }
    
    public double getDegrees(){
        return angleInDegrees;
    }
    
    public double getRadians(){
        return angleInDegrees*Math.PI / 180;
    }
    
    public void setDegrees(double degrees){
        this.angleInDegrees = degrees;
    }
    
    public void setRadians(double radians){
        this.angleInDegrees = radians*180/Math.PI;
    }

    private Angle(){}
}

このクラスの実装は、角度の表現を1つだけ保存し、必要に応じて他の角度を計算するように変更されました。

しかし、 実装は変更されましたが、インタフェースは変更されませんでした 。呼び出し側のクラスがangleInRadiansメソッドへのアクセスに依存していた場合は、新しいバージョンのAngleを使用するように変更する必要があります。クラスの呼び出しは、クラスの内部表現を気にするべきではありません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow