OOPの背後にある基本的な考え方は、データと動作(そのデータに基づく)は不可分であり、クラスのオブジェクトの考え方によって結合されるということです。オブジェクトには、それ(およびその他のデータ)で機能するデータとメソッドがあります。明らかに、OOPの原則により、単なるデータであるオブジェクト(C構造体など)はアンチパターンと見なされます。
ここまでは順調ですね。
問題は、私のコードが最近このアンチパターンの方向にますます進んでいるように見えることに気づいたことです。クラスと疎結合設計の間の情報隠蔽を達成しようとすればするほど、私のクラスは、動作クラスのない純粋なデータとデータクラスのないすべての動作の混合になります。
私は通常、他のクラスの存在に対する認識を最小限に抑え、他のクラスのインターフェイスに関する知識を最小限に抑える方法でクラスを設計します。特にトップダウン方式でこれを実施します。低レベルのクラスは高レベルのクラスについては知りません。例えば:
一般的なカードゲームAPIがあるとします。あなたにはクラスがありCard
ます。ここで、このCard
クラスはプレーヤーの可視性を決定する必要があります。
1つの方法はboolean isVisible(Player p)
、Card
クラスに参加することです。
もう1つはboolean isVisible(Card c)
、Player
クラスに参加することです。
特に、最初のアプローチは嫌いです。なぜなら、より高いレベルのPlayer
クラスに関する知識をより低いレベルのCard
クラスに与えるからです。
代わりに、3番目のオプションを選択しました。このViewport
クラスでは、指定Player
されたカードとカードのリストによって、どのカードが表示されるかが決まります。
ただし、このアプローチは、可能なメンバー関数の両方Card
とPlayer
クラスを奪います。カードの可視性以外のものに対してこれを行うとCard
、Player
すべての機能が他のクラスで実装されているため、純粋にデータを含むクラスが残りますViewport
。
これは、OOPの基本的な考え方に明らかに反しています。
正しい方法はどれですか?クラスの相互依存関係を最小化し、想定される知識と結合を最小化するが、すべての低レベルクラスにデータのみが含まれ、高レベルクラスにすべてのメソッドが含まれるという奇妙なデザインに巻き込まれないようにするにはどうすればよいですか?全体の問題を回避するクラス設計に関する3番目の解決策や視点はありますか?
PS別の例を示します。
DocumentId
不変で、単一のBigDecimal id
メンバーとこのメンバーのゲッターのみを持つクラスがあるとします。ここで、データベースからこのidをDocumentId
返すメソッドをどこかに持つ必要がありDocument
ます。
あなたは:
- クラスに
Document getDocument(SqlSession)
メソッドを追加しDocumentId
、永続性に関する知識("we're using a database and this query is used to retrieve document by id"
)、DBへのアクセスに使用されるAPI などを突然導入します。また、このクラスでは、コンパイルするために永続性JARファイルが必要になりました。 - この方法でいくつかの他のクラスを追加し
Document getDocument(DocumentId id)
たまま、DocumentId
死んだ、いや行動、構造体のようなクラスとしてクラスを。