インタビューでは、抽象化とカプセル化の違いを説明するよう求められました。私の答えは
Abstractionを使用すると、複雑な実世界を最も簡単に表現できます。これは、オブジェクトが持つべき関連する品質と動作を識別するプロセスです。つまり、背景の詳細を表すことなく必要な機能を表すことです。
カプセル化は、オブジェクトのすべての内部詳細を外部の現実世界から隠すプロセスです。 「カプセル化」という言葉は、「カプセル」に「囲む」ようなものです。抽象化の動作が実装される内部ビューをクライアントが見ることを制限します。
上記の回答で、インタビュアーは確信したと思いますが、その後、両方の目的が隠れている場合、カプセル化を使用する必要がある理由を尋ねられました。その時、私はこれに対して良い答えを持っていませんでした。
私の答えをより完全にするために何を追加すべきですか?
抽象化は、インターフェースを実装から分離することに関係しています。 (私たちはそれが何であるかを気にしません、それは特定の方法で動作しますを気にします
カプセル化は、実装の内部構造へのアクセスまたは内部構造の知識を禁止することに関係しています。 (どのように機能するかを気にする必要も、見る必要もありません。それだけです。)
カプセル化を抽象化の同義語として使用する人もいますが、これは(IMO)誤りです。インタビュアーがこれを考えた可能性があります。その場合、「カプセル化」について言及したときに、それぞれ2つの異なることについて話していました。
これらの概念は、プログラミング言語ごとに異なって表されることに注意してください。いくつかの例:
それは簡単です!
テレビの例を見てみましょう-それはEncapsulationです。なぜなら:
テレビにはさまざまな機能が搭載されていますが、それらは完全に隠されているのでわかりません。
私たちがテレビと呼ぶものにカプセル化された音楽、ビデオなどの隠されたものすべて
さて、抽象化は何かについて少し知っているときであり、それが内部的にどのように機能するかわからないものを操作するのに役立ちます。
たとえば、テレビのリモコンは抽象化です。なぜなら、
プログラム的に、なんらかの方法で隠しデータにアクセスして何かを知ることができた場合、それは抽象化です。そして、内部については何もカプセル化については知りません。
リモートがなければ、TVで何も変更できません。すべてのコントロールが非表示になっているため、何が表示されるかを確認する必要があります。
エンティティの詳細の代わりにエンティティを公開します。
「詳細はありますが、考慮していません。必要ではありません。」
さまざまな計算:加算、乗算、減算、除算、正方形、罪、コス、タン。
Sin、Cos、Tanの計算方法の詳細は示しません。電卓を表示するだけで、ユーザーが使用する必要のあるさまざまなメソッドを使用できます。
従業員には、名、姓、ミドルネームがあります。彼はLogin()、Logout()、DoWork()を実行できます。
データベースへの接続、従業員IDとパスワードの送信、データベースからの応答の受信など、従業員のログインで多くのプロセスが発生している可能性があります。上記の詳細は存在しますが、詳細を非表示にし、「従業員」のみを公開します。
囲みます。複数の特性/機能を個人ではなく1つのユニットとして扱う。そのため、外部の世界は、詳細ではなくそのユニットを直接参照します。
「詳細はありますが、それらを考慮しますが、表示するのではなく、表示する必要があるものを表示します。」
加算、減算、乗算、除算として呼び出すのではなく、計算機として呼び出します。
「John」など、すべての特性と操作が従業員によって参照されるようになりました。ジョンには名前があります。 John Can DoWork()。ジョンはLogin()できます。
実装を外部から隠す。そのため、外の世界は見られてはならないものを見ることができません。
「詳細はありますが、考慮しますが、表示しません。表示する必要はありません。」
要件:加算、減算、乗算、除算。あなたはそれを見て結果を得ることができるでしょう。
オペランドがどこに格納されているかを知る必要はありません。それはあなたの要件ではありません。
また、私が実行しているすべての命令もあなたの要件ではありません。
ジョンは出席率を知りたいです。したがって、GetAttendancePercentage()が呼び出されます。
ただし、このメソッドにはデータベースに保存されたデータが必要です。したがって、FetchDataFromDB()を呼び出します。 FetchDataFromDB()は、外の世界から見える必要はありません。
したがって、非表示にします。ただし、John.GetAttendancePercentage()は外の世界に表示されます。
抽象化、カプセル化、非表示は互いに補完します。
詳細に対する抽象化レベルを作成するため、詳細はカプセル化されます。そして、それらは囲まれているため、隠されています。
抽象化とカプセル化の違い:-
抽象化
カプセル化
カプセル化
あなたがグーグルで学んだことからのカプセル化は、関連するデータと操作を単一のカプセルにまとめる概念、またはOOPのクラスと言うことができる概念であり、他のプログラムが保持しているデータまたはメソッドの実装を変更できないようにします特定の時点で。インスタンス変数へのアクセスを提供できるのは、getterメソッドとsetterメソッドのみです。
私たちのコードは他の人によって使用される可能性があり、将来のアップグレードやバグ修正は責任を負います。カプセル化は、コード内でコードを変更しても、それを使用している他の人のコードを壊さないようにするものです。
カプセル化により、コードの保守性、柔軟性、および拡張性が高まります。
カプセル化は、インターフェイスの背後に実装を隠すのに役立ちます。
抽象化
抽象化は、インターフェースの背後に実装を実際に隠すプロセスです。そのため、実際の動作を認識しているだけで、思考が内部的にどのように機能するかは認識していません。最も一般的な例は、ロック内にキーを配置し、簡単にロックを解除するシナリオです。したがって、ここのインターフェースは鍵穴ですが、ロックのロックを解除するために、ロック内のレバーがどのように相互調整するかはわかりません。
より明確にするために、抽象化は、異なるオブジェクトに同じインターフェースを使用する機能として説明できます。同じインターフェースの異なる実装が存在する場合がありますが、すべての実装の詳細はカプセル化によって隠されます。
最後に、これまでのすべての混乱に答える声明-隠されている部分はカプセル化に関連し、公開されている部分は抽象化に関連しています。
私の前には、さまざまな例がたくさんあります。
さて、ここに私の意見があります抽象化が現実から興味を持ち始めています。
abstractionで、複雑さを軽減するために何かを隠しますそれとInencapsulationでは、データをprotectに隠します。
したがって、クラスと呼ばれる単一のエンティティ内のデータとメソッドのラッピングとしてカプセル化を定義します。
Javaでは、データとメソッドをラップするだけでなく、ゲッターとセッターを使用してカプセル化を実現しています。また、そのデータにアクセスする方法も定義します。また、データにアクセスしている間も保護します。
技術的な例は、プライベートデータ変数の呼び出しの重みを定義することです。これで、現実世界のシナリオでは重みをゼロまたはゼロ未満にすることはできません。
ゲッターとセッターがいない場合、クラスのパブリックメンバーである負の値に簡単に設定できたと想像してください。
実際の例を1つ使用した場合の最終的な違いは、
スイッチとボタンで構成される回路基板を検討してください。すべてのワイヤを回路ボックスにラップして、直接接触しないようにして誰かを保護できるようにします(encapsulation)。
これらのワイヤが互いにどのように接続されているかは気にしませんが、スイッチのオンとオフを切り替えるインターフェースが必要です。そのインターフェースは、ボタンによって提供されます(abstraction)
Abstraction:抽象化は、関連データを収集または収集し、関連性のないデータを削除するプロセスです。 (そして、抽象化を達成した場合、カプセル化も達成されます。)
カプセル化:カプセル化は、単一のユニットに関数とメンバーをラップするプロセスです。手段実装の詳細を隠しています。ユーザーがクラスのオブジェクトを作成することでアクセスできることを意味し、詳細を見ることができません。
例:
public class Test
{
int t;
string s;
public void show()
{
s = "Testing";
Console.WriteLine(s);
Console.WriteLine(See()); // No error
}
int See()
{
t = 10;
return t;
}
public static void Main()
{
Test obj = new Test();
obj.Show(); // there is no error
obj.See(); // Error:- Inaccessible due to its protection level
}
}
上記の例では、ユーザーはobj(抽象化)を使用してShow()メソッドのみにアクセスできます。
また、See()メソッドは、カプセル化されたShow()メソッドで内部的に呼び出しています。これは、Show()メソッドで何が起こっているのかユーザーが知らないためです。
カプセル化:機密文書があると仮定して、これらの文書をロッカー内に隠して、誰もアクセスできないようにします。これはカプセル化です。
抽象化:新聞にまとめられた大きな事件が起こった。現在、新聞は実際の事件のより重要な詳細のみを掲載しています。これは抽象化です。さらに、事件の見出しは、より具体的な詳細を1行で強調しているため、事件のより高いレベルの抽象化を提供します。また、フットボール/クリケットの試合のハイライトは、試合全体の抽象化と考えることができます。
したがって、カプセル化はデータの完全性を保護するために隠れており、抽象化はより重要な詳細を強調しています。
プログラミング用語で変数はプライベートとしてクラスのスコープで囲まれているため、外部から直接アクセスできないようになっていることがわかります。これはカプセル化です。一方、2つの数値を交換するために、クラスで関数を作成することもできます。一時変数を使用するか、ビット操作または算術演算のいずれかを使用して番号を交換できますが、ユーザーの目標は、交換に使用される方法に関係なく交換された番号を受け取ることです。これはabstraction。
抽象化:ハードウェア抽象化レイヤーの場合、背後にあるハードウェアの詳細を知らなくても、ハードウェアをトリガーする(例えば、左右に回す)ためのシンプルなインターフェースがあります。したがって、システムの複雑さを隠します。これは、現実世界の簡略化されたビューです。
カプセル化:オブジェクト内部の非表示。オブジェクトは、実世界の抽象化です。ただし、このオブジェクトの詳細(データ構造など)は、カプセル化によって非表示にすることができます。
抽象:「特定の目的に関連する重要な情報を抽出し、残りの情報を無視する問題の見解。」[IEEE、1983]
カプセル化:「カプセル化または同等の情報隠蔽とは、オブジェクトに必要なものをすべて含めること、さらに、他のオブジェクトがこの内部構造を認識する必要がないようにこれを行うことを指します。」
抽象化は、背景の詳細や説明を含めずに重要な機能を表す行為を指します。
カプセル化は、オブジェクトのプロパティと動作を隠し、必要に応じて外部アクセスのみを許可するために使用される手法です。他のオブジェクトがカプセル化されたオブジェクトのプロパティやメソッドを直接変更したり、アクセスしたりすることを防ぎます。
抽象化とカプセル化の違い
1.抽象化は、オブジェクト(つまり、インターフェース)の外側のビューに焦点を当てます。カプセル化(情報の隠蔽)は、抽象化の動作が実装される内側のビューをクライアントが見ることを防ぎます。
2.抽象化は、カプセル化が実装である間、設計側の問題を解決します。
3.カプセル化は抽象化の成果物です。カプセル化では、開発者のニーズに合わせて抽象化をグループ化することについてはほとんど説明しません。
抽象化は、データのカプセル化の多くの利点の1つです。 Data EncapsulationはAbstractionを実装する1つの方法と言うこともできます。
私の考えでは、カプセル化は、アクセス指定子を使用してプログラムコードの複雑さを隠すというプログラマーの考えです。
抽象化とは、機能と動作に応じてメソッドとオブジェクトを分離することです。たとえば、車にはシート、ホイール、ブレーキ、ヘッドライトがあります。
abstractionの概念を本質的に利用している開発者Aは、whatのみに関係するモジュール/ライブラリ関数/ウィジェットを使用しますそれは(そしてwhat使用されます)、しかしhowではありませんそれをします。そのモジュール/ライブラリ関数/ウィジェット(開発者Aがプル/プッシュを許可されている「レバー」)のインターフェースは、その抽象化の擬人化です。
そのようなモジュール/関数/ウィジェットを作成しようとしている開発者Bは、カプセル化の概念を利用して、開発者A(およびウィジェットを使用する他の開発者)が結果を活用できるようにします- 抽象。開発者Bは、ウィジェットが何をするかhowに最も確実に関心を持っています。
TLDR;
(緩やかな一般化として、何かを抽象化するには、何か他のものをカプセル化する必要があります。そして、何かをカプセル化することにより、抽象化を作成しました。)
私の意見の抽象化は、実装や背景の詳細を隠すという意味ではありません!
抽象化により、現実世界の表現を扱うメリットが得られます。これは、扱いやすく、再利用する能力があり、多かれ少なかれ複雑なプログラムパッケージの他のコンポーネントと組み合わせることができます。そのため、how
を見つけて、現実世界の完全な平和を選択する必要があります。これは、アルゴリズムとデータの意味を表すのに十分なものです。インターフェースの実装は詳細を隠すかもしれませんが、これは何かを抽象化するためにしなければならない作業の一部ではありません。
私にとって抽象化の最も重要なことは次のとおりです。
これはすべて、背景の詳細を隠すこととは関係ありません!
一部のデータをソートすることを考えている場合、抽象化の結果は次のようになります。
これらはすべて、情報を隠すこととは関係ありません。
抽象化:データを非表示にします。 カプセル化:データをバインドします。
IOSに関する限り、Objective Cファイル(つまり.hおよび.m)はカプセル化と同様に抽象化も使用していると言えます。
抽象化
ヘッダーファイル(.h)は、関数とパブリックメンバーのみを外部に公開します。実装ファイルを持たない限り、どのように使用されるかは誰にもわかりません。すべての使用法と実装ロジックを自己保持するのは.mファイルです。 「実装は未公開のままです」。
カプセル化
プロパティ(@property)は、iVarのメモリ管理属性(アトミック、ストロング、保持、ウィーク)をカプセル化します。
カプセル化は基本的に、内部実装へのアクセスまたは外部世界への内部に関する知識を拒否しますが、Abstractionは外部世界との対話を支援する実装の一般化されたビューを提供しますそれと
カプセル化する理由なぜ抽象化するのですか?
以下の質問から始めましょう。
1)コードがフィールドに直接アクセスできるようにするとどうなりますか? (直接許可とは、フィールドpublicを作成することを意味します)
例でこれを理解してみましょう。
following is our BankAccount class and following is its limitation
*Limitation/Policy* : Balance in BankAccount can not be more than 50000Rs. (This line
is very important to understand)
class BankAccount
{
**public** double balanceAmount;
}
Following is **AccountHolder**(user of BankAccount) class which is consumer of
**BankAccount** class.
class AccountHolder
{
BankAccount mybankAccount = new BankAccount();
DoAmountCreditInBankAccount()
{
mybankAccount.balanceAmount = 70000;
/*
this is invalid practice because this statement violates policy....Here
BankAccount class is not able to protect its field from direct access
Reason for direct access by acount holder is that balanceAmount directly
accessible due to its public access modifier. How to solve this issue and
successfully implement BankAccount Policy/Limitation.
*/
}
}
コードの他の部分がbalanceAmountフィールドに直接アクセスし、残高を70000Rに設定した場合、これは受け入れられません。この場合、コードの他の部分がbalanceAmountフィールドにアクセスするのを防ぐことはできません。
だから私たちにできることは?
=>答えは、balanceAmountフィールドをプライベートにして、他のコードが直接アクセスできないようにし、balanceAmountフィールドを操作するpublicメソッドを介してのみそのフィールドへのアクセスを許可することです。メソッドの主な役割は、フィールドを50000Rを超えて初期化できないように、メソッド内にいくつかの防止ロジックを記述できることです。ここでは、balanceAmountと呼ばれるデータフィールドと、そのフィールドで動作するメソッドとのバインディングを作成しています。このプロセスはカプセル化と呼ばれます(プライベートなどのアクセス修飾子を使用してフィールドを保護することがすべてです)
カプセル化は抽象化を実現する1つの方法です。 =>このメソッドのユーザーは、彼/彼女が呼び出すメソッドの実装(どのように金額が入金されるのか?ロジックとそのすべて)を知らないでしょう。ユーザーが実装の詳細を知らないことは、抽象化(ユーザーから詳細を隠す)と呼ばれます。
Following will be the implementation of class:
class BankAccount
{
**private** double balanceAmount;
**public** void UpdateBankBalance(double amount)
{
if(balanceAmount + amount > 50000)
{
Console.WriteLine("Bank balance can not be more than 50000, Transaction can
not be proceed");
}
else
{
balanceAmount = balanceAmount + amount;
Console.WriteLine("Amount has been credited to your bank account
successfully.....");
}
}
}
class AccountHolder
{
BankAccount mybankAccount = new BankAccount();
DoAmountCreditInBankAccount()
{
mybankAccount.UpdateBankBalance(some_amount);
/*
mybankAccount.balanceAmount will not be accessible due to its protection level
directly from AccountHolder so account holder will consume BankAccount public
method UpdateBankBalance(double amount) to update his/her balance.
*/
}
}
私の意見では、両方の用語は何らかの意味で関連しており、互いに混ざり合っています。 「カプセル化」は、関連するフィールド、クラス(またはモジュール)内のメソッドをグループ化して、関連するものをまとめる方法を提供します。その時点では、2つの方法でデータを非表示にします。
アクセス修飾子を介して。
純粋にクラス/オブジェクトの状態を隠すため。
いくつかの機能を抽象化します。
a。インターフェイス/抽象クラスを介して、カプセル化されたクラスまたはモジュール内の複雑なロジックを抽象化/一般化して、外部で使用できます。
b。関数の署名を通じて。はい、抽象化の関数署名の例ですら。呼び出し元は署名とパラメーター(存在する場合)のみを知っており、関数の実行方法については何も知らないためです。返される値のみを考慮します。
同様に、「抽象化」は、振る舞いをインターフェース(または抽象クラス、または通常のクラス)にグループ化/ラップするという観点からカプセル化の方法を考えているかもしれません。
カプセル化は2つの主な理由で使用されます:
1.)データの非表示と保護(クラスのユーザーは、提供されたメソッドを使用しない限り、データを変更できません)。
2.)データを操作するために使用されるデータとメソッドを1つのエンティティ(カプセル)に結合する。 2番目の理由は、インタビュアーが聞きたかった答えだと思います。
一方で、抽象化は必要な情報のみをユーザーに公開し、不要な詳細を非表示にするために必要です(たとえば、メソッドの実装を非表示にし、実装が影響を受ける場合にユーザーが影響を受けないようにします)かわった)。
プログラムには、主に2つの部分があります:DATAとPROCESS。抽象化はプロセス中のデータを隠し、だれも変更できないようにします。カプセル化は、表示できないようにデータをあらゆる場所に隠します。これがあなたの疑問を明らかにすることを願っています。
抽象化に関する重要なことは、クライアントコードがdifferent論理/抽象モデルの観点から動作することです。その異なるモデルは、特定のクライアントの使用法で実装が起こるよりも複雑または少ないかもしれません。
たとえば、「イテレータ」は、0以上の値のシーケンスされたトラバーサルを抽象化(別名)します。C++では、begin()
、*
/->
(逆参照)、end()
、pre/post ++
および場合によっては--
として現れます、+
、+=
、[]
、std::advance
などがあります。クライアントが配列に沿ってsize_t
をインクリメントすると言うことができれば、それは多くの手荷物です。重要なことは、抽象化により、このようなトラバースを実行する必要があるクライアントコードを、要素を提供する「コンテナ」またはデータソースの正確な性質から切り離すことができるということです。反復は、トラバーサルの実行方法を制限する高レベルの概念です(たとえば、前方反復子は一度に要素を進めることしかできません)が、データはより大きなソースのセット(たとえば、キーボードから)同時に保存される値の意味で「コンテナ」さえありません)。クライアントコードは、通常、最小限またはまったく変更せずに、独自のイテレータで抽象化された別のデータソースに切り替えることができ、さらに std::iterator_traits<Iterator>::value_type
利用できます。
これは、パブリックインターフェイスでの操作の結果として間接的にしか使用されないことがわかるように、一部のデータまたは関数をアクセスしにくくする慣行であるカプセル化とはまったく異なります。カプセル化は、オブジェクトのinvariantsを維持するために不可欠なツールです。つまり、すべてのパブリック操作の後、クライアントコードが届くだけの場合はtrueを維持することを意味します。オブジェクトを変更すると、不変条件を強制できなくなります。たとえば、クラスは文字列をラップし、操作後に小文字が大文字に変更されるようにしますが、クライアントコードが到達してクラスのメンバー関数の関与なしに文字列に小文字を入れることができる場合、不変条件を強制することはできません。
違いをさらに強調するために、含まれるオブジェクトに対する操作によって偶発的に生成されるprivate
std::vector<Timing_Sample>
データメンバーを考えてみましょう。破棄時にレポートがダンプされます。データおよびデストラクタの副作用がオブジェクトのクライアントコードと相互作用せず、オブジェクトに対する操作が意図的に時間管理動作を制御しないため、その時間レポート機能の抽象化はありませんが、カプセル化があります。抽象化の例は、タイミングコードをvector
をカプセル化する(private
にする)別のクラスに移動し、add(const Timing_Sample&)
やreport(std::ostream&)
のようなインターフェイスを提供することです。 -このようなインストルメンテーションの使用に関連する必要な論理/抽象操作。抽象化されたコードは、同様の機能ニーズを持つ他のクライアントコードで再利用できることが非常に望ましい副作用があります。