88

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

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

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

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


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

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

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

4

3 に答える 3

91

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

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

たとえば、Java 開発者はFileInputStreamの機能を気にせずに高レベルの機能を利用できます (つまり、ファイル ハンドル、ファイル システムのセキュリティ チェック、メモリ割り当て、およびバッファリングは内部で管理され、コンシューマには隠されます)。これにより、 の実装をFileInputStream変更できます。また、API (インターフェース) が一貫している限り、FileInputStream以前のバージョンに対してビルドされたコードは引き続き機能します。

同様に、独自のクラスを設計するときは、内部の実装の詳細をできるだけ隠したいと思うでしょう。

Booch の定義1では、 OO カプセル化はInformation Hidingによって実現されます。具体的には、クラス インスタンスが所有する内部データ (状態を表すフィールド/メンバー) を非表示にすることで、制御された方法で内部データへのアクセスを強制し、直接、これらのフィールドへの外部変更、およびクラスの内部実装メソッドを非表示にします (たとえば、それらを非公開にすることによって)。

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

情報隠蔽が適用されていない例 (Bad Practice) :

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(非抽象) サブクラスのみをインスタンス化できます。おそらく、Abstractionと の間の混同の原因の 1 つabstract classは、オブジェクト指向の初期の頃、コードの再利用を実現するために継承がより頻繁に使用されていたことです (たとえば、関連付けられた抽象基本クラス)。今日では、構成は一般に継承よりも好まれており、インターフェース、イベント/デリゲート/関数、トレイト/ミックスインなどを介して抽象化を実現するために利用できるツールが増えています.

Re : カプセル化 vs 情報隠蔽

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

ウィキペディアを引用:

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

たとえば、声明では

データ アクセス コードを独自のクラスにカプセル化しました。

..カプセル化の解釈は、懸念の分離または単一責任プリンシパル(SOLID の「S」)とほぼ同等であり、リファクタリングの同義語として使用できる可能性があります。


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

于 2012-08-15T08:20:58.110 に答える
52

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

于 2012-08-15T08:47:15.767 に答える
37

抽象化とは、共通点を特定し、コードのさまざまなレベルで使用する必要がある機能を削減することです。

たとえば、Vehicleクラスがあるかもしれません。Aは、 aと同様に、Cara から派生します。それぞれに車輪や乗客などの数を尋ねることができます。その情報は抽出され、とから共通のものとして識別されています。VehicleMotorbikeVehicleCarsMotorbikes

私のコードでは、多くの場合、一般的なメソッドなどを介して処理することができます。Vehicles後で新しい車両タイプを追加すると (例: )、コードの大部分はこの事実に気付かないままになり、単独での実装は特殊性を心配します。go()stop()ScooterScooterScooter

于 2012-08-15T08:10:46.430 に答える