自己カプセル化

2017年3月9日

データカプセル化は、オブジェクト指向スタイルの中心的な原則です。これは、オブジェクトのフィールドを公開してはならず、オブジェクト外部からのアクセスはすべてアクセサメソッド(ゲッターとセッター)を介して行うべきであることを意味します。公開アクセス可能なフィールドを許可する言語もありますが、通常、プログラマはこれを行わないよう注意を促します。自己カプセル化はさらに一歩進んでおり、データフィールドへのすべての内部アクセスもアクセサメソッドを介して行うべきであることを示しています。データ値自体にアクセスできるのは、アクセサメソッドのみです。データフィールドが外部に公開されていない場合、これは追加のプライベートアクセサを追加することを意味します。

これは、適切にカプセル化されたJavaクラスの例です。

class Charge…

  private int units;
  private double rate;

  public Charge(int units, double rate) {
    this.units = units;
    this.rate = rate;
  }
  public int getUnits() { return units; }
  public Money getAmount() { return Money.usd(units * rate); }

両方のフィールドは不変です。unitsフィールドはゲッターを介してクラスのクライアントに公開されていますが、rateフィールドは内部でのみ使用されるため、ゲッターは必要ありません。

自己カプセル化を使用したバージョンを次に示します。

class ChargeSE…

  private int units;
  private double rate;

  public ChargeSE(int units, double rate) {
    this.units = units;
    this.rate = rate;
  }
  public int getUnits()    { return units; }
  private double getRate() { return rate; }
  public Money getAmount() { return Money.usd(getUnits() * getRate()); }

自己カプセル化とは、getAmountがゲッターを介して両方のフィールドにアクセスする必要があることを意味します。これはまた、rateのゲッターを追加する必要があることを意味し、それをプライベートにする必要があります。

可変データのカプセル化は、一般的に良い考えです。更新関数は、検証とそれに伴うロジックを実行するコードを含めることができます。関数を介したアクセスを制限することで、Uniform Access Principleをサポートし、どのデータが計算され、どのデータが格納されているかを隠すことができます。これらのアクセサにより、同じ公開インターフェースを維持しながら、データ構造を変更できます。さまざまな種類のAccess Modifierによってオブジェクトの「外部」が何であるかについては、言語によって詳細が異なりますが、ほとんどの環境では何らかの程度でデータカプセル化がサポートされています。

自己カプセル化を義務付けるいくつかの組織に出会ったことがあります。それを使用するかどうかは、90年代から定期的に議論される話題でした。その支持者は、カプセル化は非常に有益であるため、内部アクセスにも組み込むべきだと主張しました。反対者は、それは不要な儀式であり、何が起こっているかを曖昧にする不要なコードにつながると主張しました。

これに対する私の見解は、ほとんどの場合、自己カプセル化にはほとんど価値がないということです。カプセル化の価値は、データアクセスのスコープに比例します。クラスは通常小さく(少なくとも私のクラスはそうです)、そのスコープ内では直接アクセスが問題になることはありません。ほとんどのアクセサは、セッターの場合は単純な代入、ゲッターの場合は取得であるため、内部でそれらを使用することにはほとんど価値がありません。

しかし、自己カプセル化が努力に見合う一般的な状況があります。セッターにロジックがある場合、内部の更新についても検討することをお勧めします。もう1つの状況は、クラスが継承構造の一部である場合であり、その場合、アクセサはサブクラスが動作をオーバーライドするための貴重なフックポイントを提供します。

そのため、私の最初の動きは通常、フィールドへの直接アクセスを使用することですが、状況がそれを要求する場合は、Self Encapsulate Fieldを使用してリファクタリングします。自己カプセル化を検討させる要因の多くは、新しいクラスを抽出することで解決できます。

参考資料

Kent Beckは、Implementation PatternsSmalltalk Best Practice Patternsの両方で、直接アクセスと間接アクセスという名前でこれらのトレードオフについて説明しています。

謝辞

Ian Cartwright、Matteo Vaccari、Philip Duldigがこの投稿の下書きについてコメントしてくれました。