web-dev-qa-db-ja.com

Javaの抽象化とカプセル化

可能性のある複製:
抽象化VS情報隠蔽VSカプセル化

私はこの質問がこのフォーラムで何千回も尋ねられたかもしれないことを知っています、ネットでさえこれらの概念に関する多くの定義で満たされていますが、すべて同じように聞こえ、すべて同じ技術用語を使用しています。たとえば、次の定義

カプセル化は、データとデータを操作して単一のエンティティに結合するコードをバインドまたはラップするプロセスです。これにより、データが外部インターフェイスや誤用から保護されます。カプセル化について考える1つの方法は、ラッパーの外側で定義された他のコードがコードとデータに勝手にアクセスするのを防ぐ保護ラッパーとしての方法です。

上記の定義から理解したことは、変数を作成し、プライベートとしてマークし、それらの変数のゲッターセッターを生成し、オブジェクトを使用してそれらのゲッターとセッターにアクセスすることです。このようにして、データはオブジェクト内に隠され、オブジェクトを介してのみアクセス可能になります。 私は正しいことを願っています


AbstractionはJavaのプロセスであり、特定の詳細を非表示にしてオブジェクトの本質的な機能のみを表示するために使用されます。つまり、オブジェクト(インターフェイス)の外側のビューを処理します。

今、これはいつも私を混乱させる部分です。私が抽象化について考えるときはいつでも、私の頭に浮かぶのは、Abstractクラスです(両方にAbstractキーワードがあるためかもしれません)。上記の定義では、抽象化とはデータを非表示にし、必要な詳細のみを表示することを意味しますが、それがカプセル化ですでに行っていることです。違いは何ですか。また、オブジェクトの外側のビューを扱うオブジェクトの外側のビューを取得できませんでした。

誰かが実際の例を使って、または可能であればプログラムの例を使って、これにもっと光を当ててください。

84
Sandeep Kumar

OO抽象化 は、クラスレベルの設計中に発生します。目的は実装の複雑さを隠す ofhow基本的な実装にアクセスするための「インターフェース」を簡素化するという意味で、API /設計/システムによって提供される機能が実装されました。

抽象化のプロセスは、ますます「上位」レベルのクラス(レイヤー)で繰り返すことができます。これにより、コードの複雑さや各レイヤーでの理解を増やさずに大規模システムを構築できます。

たとえば、Java開発者は、 FileInputStream の高レベル機能を使用できます。その動作方法(ファイルハンドル、ファイルシステムセキュリティチェック、メモリ割り当て、バッファリングなど)内部で管理され、消費者から隠されている)。これにより、FileInputStreamの実装を変更できます。また、FileInputStreamへのAPI(インターフェース)の一貫性が保たれている限り、以前のバージョンに対してビルドされたコードは引き続き機能します。

同様に、独自のクラスを設計する場合、内部実装の詳細を可能な限り他の人から隠したいでしょう。

Booch定義では1OOカプセル化は、 情報の隠蔽 によって実現され、特にクラスインスタンスが所有する内部データ(状態を表すフィールド/メンバー)の隠蔽について、制御された方法で内部データへのアクセスを強制し、これらのフィールドへの直接の外部変更を防止し、クラスの内部実装メソッドを非表示にします(プライベートにするなど)。

たとえば、クラスのフィールドはデフォルトでprivateにすることができ、これらへの外部アクセスが必要な場合にのみ、get()および/またはset()(またはProperty)がクラスから公開されます。 (現代のOO言語では、フィールドはreadonly/final/immutableとしてマークできます。これにより、クラス内であっても変更がさらに制限されます)。

情報の非表示が適用されていない例(悪い練習)

class Foo {
   // BAD - NOT Encapsulated - code external to the class can change this field directly
   // Class Foo has no control over the range of values which could be set.
   public int notEncapsulated;
}

フィールドのカプセル化が適用された例

class Bar {
   // Improvement - access restricted only to this class
   private int encapsulatedPercentageField;

   // The state of Bar (and its fields) can now be changed in a controlled manner
   public void setEncapsulatedField(int percentageValue) {
      if (percentageValue >= 0 && percentageValue <= 100) {
          encapsulatedPercentageField = percentageValue;
      }
      // else throw ... out of range
   }
}

フィールドの不変/コンストラクタのみの初期化の例

class Baz {
   private final int immutableField;

   public void Baz(int onlyValue) {
      // ... As above, can also check that onlyValue is valid
      immutableField = onlyValue;
   }
   // Further change of `immutableField` outside of the constructor is NOT permitted, even within the same class 
}

Re:抽象化vs抽象クラス

抽象クラ​​ス は、クラス間の共通性の再利用を促進するクラスですが、それ自体はnew()で直接インスタンス化することはできません-抽象クラスはサブクラス化する必要があり、concrete(非抽象)サブクラスのみをインスタンス化できます。おそらくAbstractionabstract classの間の混乱の原因の1つは、OOの初期には、コードの再利用を実現するために継承がより頻繁に使用されることでした(たとえば、関連する抽象基本クラスと)。最近では、 構成は一般的に継承よりも好まれます であり、インターフェース、イベント/デリゲート/関数、特性/ミックスインなどを通じて、抽象化を実現するために利用できるツールがさらにあります。

再:カプセル化と情報隠蔽

encapsulationの意味は時間の経過とともに進化したように見えますが、最近では encapsulation もより一般的に使用できますどのメソッド、フィールド、プロパティ、イベントなどをbundleに決定するかという一般的な意味。

ウィキペディアの引用:

オブジェクト指向プログラミング言語のより具体的な設定では、この概念は、情報隠蔽メカニズム、バンドルメカニズム、またはこの2つの組み合わせのいずれかを意味するために使用されます。

たとえば、次のステートメント

encapsulated独自のクラスへのデータアクセスコード

..encapsulationの解釈は、 Separation of Concerns または Single Responsibility Principal ( "S" SOLID)であり、おそらくリファクタリングの同義語として使用できます。


[1] Boochの encapsulation cat picture を見たら、カプセル化を忘れることはできません-アプリケーション指向オブジェクト指向分析および設計のp46、第2版

83
StuartLC

簡単に言うと、何を実装するかを決めるときに抽象化を行います。実装したものを隠すときにカプセル化を行います。

49
mbm

抽象化とは、共通性の特定であり、コードのさまざまなレベルで作業しなければならない機能を削減することです。

例えばVehiclename__クラスがあります。 Carname__は、Vehiclename__から派生するように、Motorbikename__から派生します。各Vehiclename__に車輪、乗客などの数を尋ねることができ、その情報は抽象化され、Carsname__およびMotorbikesname__から共通として識別されています。

私のコードでは、よくVehiclesname__を一般的なメソッドgo()stop()などで処理できます。後で新しいVehicleタイプ(たとえばScootername__)を追加すると、コードの大部分はこの事実を無視し、Scootername__の実装だけでScootername__細目。

32
Brian Agnew