web-dev-qa-db-ja.com

OOP-このデータは非表示ですか?

私はデータの隠蔽について読んでいて、その定義が少し異なるようですので、実用的な例を考え出そうとすると、私が正しいことをしているかどうかわかりません。

これまでのところ、データを非表示にすると、予期しない方法でデータにアクセスできないようになります。これにより2つの異なるケースが考えられますが、これらが実際にデータの非表示を記述しているか、それとも他の何かを記述しているかはわかりません。

  1. GymクラスとMemberクラスがあるとします。 Gymクラスには、membersと呼ばれるcontainerのMemberオブジェクトがあります。したがって、Pythonを使用している場合は、メンバーのリストになる可能性があります。しかし、gym.members.append(new_member)を実行してメンバーをジムに追加すると、コンテナーの実際の実装が明らかになります。たとえば、メンバーを追加したすべての行を見つけて置換する必要があるため、ある時点でリストの使用を中止して辞書の使用を開始したい場合、これは問題を引き起こす可能性があります。したがって、これを回避するには、addMember(self, member)というメソッドを作成して、Gymクラス内で内部的に実装を管理できるようにします。
  2. もう1つのケースは、属性値を直接変更したくない場合です。これは、前にいくつかのチェックを行う必要があるためです。最初の例を拡張して、MemberクラスにactiveおよびlastPayment属性もあるとします。ここで、activeは、ジムのときに真に設定されたブール値ですメンバーシップはアクティブで、それ以外の場合はFalseです。lastPaymentは、ジムメンバーが最後に支払った日付です。最後のお支払いが1か月以上前に行われた場合、メンバーシップは自動的にactive=Falseに設定され、その後、新しい支払いが行われた場合にのみTrueに設定されます。つまり、activeの値は、member.active=Falseを実行して直接変更しないでください。したがって、その場合は__activeという名前を付けてこの属性を保護します。

したがって、これらは2つの異なるケース(実際の実装を明らかにし、偶発的な変更を防止する)であり、データ非表示を表すために理解しています。両方がデータ非表示の2つの異なる例にすぎないのか、それとも誤解があり、何かを説明しているのかわかりません。そうしないと。

3
Floella

データまたは情報の非表示とは、クラス変数を他のクラスからアクセスできないようにすることを指します。 Javaおよびその他の多くの言語では、変数を「プライベート」として宣言することでこれを行います。Pythonでは、変数の前に二重の下線を付けます。あなたは、どちらもデータ非表示の有効な使用例です。

4
Nikhil Satiani

技術的な定義は、それを適用する理由よりも明確ではない場合があります。あなたの番号2は、データ隠蔽のもう1つの特性/能力であり、それを適用する理由ではありません。

データの非表示は、内部設計が後で変更される場合の影響を最小限に抑えることを目的としたカプセル化と分離の形式です。システム全体への影響を最小限に抑えながら、内部で物事を移動できるようにするために、クライアントがデータに直接ではなくインターフェースと対話するようにします。したがって、あなたのナンバー1の例はもっと重要です。

1
Martin Maat

このデータは非表示ですか?

はい、そうです。

まだよくわからないですが、概念を理解したようです。それはあなたの質問に対する完全で直接的な答えです。

もう少し詳細

実装の変更について心配していましたが、それは当然の懸念事項です。ただし、そこにはさらに厄介な驚きがあります。このようなコードを想像してください:

temporary_list = gym.members

# temporary_list gets passed around, until, somewhere else entirely:
temporary_list.append(new_member)

ランダムな任意のコードによって、クラスが内部で持つ可能性のあるすべてのルールをバイパスして、Gymに新しいメンバーを追加できるようになりました。

これは現実の世界によく対応しています。ジムがメンバーのリストを誰かに渡した場合、明らかにそれはコピーにすぎず、収入やフィットネスステーションのメンテナンスの必要性などを決定するために内部で使用される「マスターリスト」ではありません。

一般に

実世界のメタファーは、与えられた例でうまく機能しますが、常にそうであるとは限りません。重要な部分は、他のコードがオブジェクトの fields にアクセスできないことです*。彼らに起こることはすべて、クラスの条件で独占的に起こります。


*オブジェクトはデータを隠し、機能を公開します。ただし、おそらくアプリケーションでいくつかのDTO(データ転送オブジェクト)も使用します。名前の最後に「オブジェクト」も付いていますが、完全に反対です。データを公開し、機能はありません。明らかに、これらで進行中のデータ非表示はなく、それで問題ありません(Javaプログラマーは、これらにゲッターとセッターの束を配置することを好みますが、技術的にはメソッドです)。

1
R. Schmitz

これらの実践の背後にある根本的な理由を理解することは、すべてを理解するのに役立つというマーティン・マートの発言に同意します。 data非表示ではなく、戦略的に非表示にする実装の詳細(内部で使用するデータ構造の選択だけでなく、動作を実装する方法-つまり、何かを呼び出すと、内部で何が起こるか)。これがカプセル化の意味です。

カプセル化は、次の意味で戦略的です。問題についての知識に基づいて、(プログラマー/デザイナーとして)あなたは、公開されているものと隠されているものを区別します。

クライアントコード(クラスを直接呼び出すコード)は、パブリックのものに関してのみ記述されます。これは、クラスのパブリックインターフェースと呼ばれるもので、パブリックメソッドのセット、それらのパラメーター、戻り値の型、これらのメソッドの意味、および(クライアントコードから「見える」)動作を指定します。

クラスのプライベートなencapsulated側面には、クラス内ですべてがどのように機能するかの詳細が含まれます-データ構造、すべてを実現するコード、クラス自体がすべての作業を行っている場合、または他のオブジェクトを呼び出す場合など.

アイデアは、クライアントコードがパブリックインターフェイスに対して作成されているため、プライベート実装の詳細を個別に変更できることです(使用されるアルゴリズム、状態の格納方法、データ構造の選択、他のクラス/オブジェクトを呼び出す場合など)。そうではありません)、外部から見える動作が、定義したパブリックインターフェイスに準拠している限り(つまり、クライアントコードの場合、異なる実装は同じように見えます)。

したがって、その意味では、パブリックインターフェイスはabstractionです。これは、クライアントコードがクラスと相互作用する方法とそれらの相互作用の意味を定義しますが、すべての実装方法の正確な詳細を指定しません(時には、それはcontractを2つの間で定義していると言います)。これにより、クライアントコードがこれらの詳細から独立し、呼び出し元(および場合によっては呼び出し元の呼び出し元など)にカスケード効果を処理する必要なく実装を変更できます。

この観点から物事を見ると、どちらの例もカプセル化に関係していますが、微妙な違いがあります。

(1.)で公開した内容(契約の一部)は、クライアントコードでメンバーを追加できるという事実ですが、それらを内部に格納する実際のデータ構造(およびそのプロセスに関連するすべてのコード)を非公開にしました、発信者にそれらがすべきではないであることを想定して通知する(つまり、現在の実装ではリストが使用されているという事実に依存する方法でコードを記述すべきではない)。

(2.)では、このクラスのコントラクトには、あなたが記述した動作が含まれます。この種のことは(一般的に)パブリックメソッド/プロパティのセットを調べるだけでは理解できないことに注意してください。クラスのドキュメントも調べる必要があります。メソッドの意味やセマンティクスについて話すとき、それが私たちが言及するものです-コントラクトは、コードで表現できる以上のものを含むことができます。したがって、この場合、どのクライアントコードでもexpectが可能であり、クラスのすべての実装がこの動作に準拠することになります。つまり、クライアントコードは依存で記述できるということです。したがって、この動作を確実にするためにこれらのチェックを行っているという事実は、それ自体がカプセル化を構成するものではありません。クラスdid n'tがそのように動作する場合、それは壊れるでしょう-それはしません想定されていることを実行します(バグになります)。それは私が述べた微妙な違いです。 isここにカプセル化されるものはthe wayこのチェックを内部で実行すること、これらの属性が実際に格納される方法(さまざまな方法で実行できるため)などです。

1