「深い構成階層」も悪くないですか?


19

「構成階層」が問題でない場合はおApびしますが、質問でそれが何を意味するのかを説明します。

「継承階層をフラットに保つ」や「継承よりも合成を優先する」などのバリエーションに遭遇していないオブジェクト指向プログラマーはいません。ただし、深い構成階層にも問題があるようです。

実験の結果を詳述するレポートのコレクションが必要だとしましょう:

class Model {
    // ... interface

    Array<Result> m_results;
}

各結果には特定のプロパティがあります。これらには、実験の時間と、実験の各段階からのメタデータが含まれます。

enum Stage {
    Pre = 1,
    Post
};

class Result {
    // ... interface

    Epoch m_epoch;
    Map<Stage, ExperimentModules> m_modules; 
}

いいですね 現在、各実験モジュールには、実験の結果を説明する文字列と、実験サンプルセットへの参照のコレクションがあります。

class ExperimentalModules {
    // ... interface

    String m_reportText;
    Array<Sample> m_entities;
}

そして、各サンプルには...まあ、あなたは絵を取得します。

問題は、アプリケーションドメインのオブジェクトをモデリングしている場合、これは非常に自然なフィットのように思えますが、結局のところ、a Resultは単なるデータの無意味なコンテナです!それのためにクラスの大きなグループを作成することは価値がないようです。

上記のデータ構造とクラスがアプリケーションドメインの関係を正しくモデル化すると仮定すると、深い構成階層に頼ることなく、そのような「結果」をモデル化するより良い方法はありますか?そのようなデザインが良いデザインかどうかを判断するのに役立つ外部コンテキストはありますか?


外部コンテキスト部分を理解しないでください。
Tulainsコルドバ

@TulainsCórdova私がここで尋ねようとしているのは、「深い構図が良い解決策である状況はありますか?」です。
-AwesomeSauce

答えを追加しました。
Tulainsコルドバ

5
はい、正確に。ある機能集約戦略を別の機能集約戦略に変更したからといって、人々が継承を構成に置き換えることで解決しようとする問題は魔法のように消えません。どちらも複雑さを管理するためのソリューションであり、その複雑さは依然として存在しており、何らかの方法で処理する必要があります。
メイソンウィーラー

3
ディープデータモデルに問題はありません。しかし、各レイヤーは1:Nの関係であるため、継承を使用してこれをどのようにモデル化できたかもわかりません。
usr

回答:


17

これがデメテル法則/最小知識の原則に関するものです。のユーザーは、自分の作業を行うためのインターフェイスModelについて必ずしも知っている必要はありませんExperimentalModules

一般的な問題は、クラスが別の型を継承するか、何らかの型のパブリックフィールドを持っている場合、またはメソッドがパラメーターとして型を取るか型を返す場合、それらすべての型のインターフェイスがクラスの有効なインターフェイスの一部になることです。問題は次のとおりです。私が依存しているこれらのタイプ:クラスのポイント全体を使用していますか それとも、私が誤って公開した実装の詳細だけですか?それらが実装の詳細である場合、クラスを公開するだけで、クラスのユーザーがそれらに依存できるようになったためです。クライアントは実装の詳細と密接に結びついています。

したがって、結束を改善したい場合は、ユーザーに自分のプライベート構造に到達するように要求する代わりに、有用なことを行うメソッドをさらに記述することにより、この結合を制限できます。ここでは、結果を検索またはフィルタリングする方法を提供します。これにより、インターフェイスを壊すことなく内部表現を変更できるため、クラスのリファクタリングが容易になります。

しかし、これにはコストがかかります。露出されたクラスのインターフェイスは、必ずしも必要ではない操作で肥大化します。これは、インターフェイスの分離の原則に違反します。ユーザーが実際に使用するよりも多くの操作に依存するように強制するべきではありません。そして、そこがデザインが重要なのです。デザインとは、あなたの文脈においてより重要な原則を決定し、適切な妥協点を見つけることです。

複数のバージョン間でソースの互換性を維持する必要があるライブラリを設計するときは、最小知識の原則をより注意深く守る傾向があります。自分のライブラリが別のライブラリを内部で使用している場合、そのライブラリで定義されたものをユーザーに公開することはありません。内部ライブラリからインターフェイスを公開する必要がある場合は、単純なラッパーオブジェクトを作成します。ここでは、ブリッジパターンやファサードパターンなどのデザインパターンが役立ちます。

しかし、私のインターフェースが内部でのみ使用される場合、または公開するインターフェースが非常に基本的なものである場合(標準ライブラリの一部、または変更する意味がないほど基本的なライブラリの一部)、非表示にするのは無意味ですこれらのインターフェース。いつものように、万能の答えはありません。


あなたは私が抱えていた大きな懸念に言及しました。より高い抽象化レベルで何か有用なことをするために、実装に深く到達しなければならなかったという考え。非常に有益な議論、ありがとう。
-AwesomeSauce

7

「深い構成階層」も悪くないですか?

もちろん。ルールは、実際には「すべての階層を可能な限りフラットに保つ」と言う必要があります。

しかし、深い構成階層は、深い継承階層よりも脆弱ではなく、変更に対してより柔軟です。直感的には、これは驚くことではありません。家族階層も同じです。血縁者との関係は遺伝学で決まっています。あなたの友人やあなたの配偶者との関係はそうではありません。

あなたの例は私を「深い階層」とは思わない。フォームは、x座標とy座標から継承する一連のポイントから継承する四角形から継承しますが、まだ完全な頭角をたどっていません。


4

アインシュタインの言い換え:

すべての階層を可能な限りフラットにしますが、フラットではありません

モデリングしている問題がそのようなものである場合、それをそのままモデリングすることに不安を抱いてはいけません。

アプリは単なる巨大なスプレッドシートであり、構成階層をそのままモデリングする必要はありません。それ以外の場合は行います。物事が無限に深いとは思わない。そのようなコレクションにデータを取り込むのが高価な場合、コレクションを返すゲッターをレイジーに保つだけです。たとえば、コレクションをデータベースからプルするリポジトリにそれらを要求するなどです。怠け者というのは、必要になるまでそれらを投入しないでください。


1

はい、リレーショナルテーブルのようにモデル化できます

Result {
    Id
    ModelId
    Epoch
}

多くの場合、プログラミングが簡単になり、データベースへのマッピングが簡単になります。しかし、あなたの関係のハードコーディングを失うことを犠牲にして


0

Javaはすべてがオブジェクトであるという考えに基づいて構築されているため、Javaでこれを解決する方法はあまりわかりません。データBLOBの型は異種(タイムスタンプ+リスト、または文字列+リストなど)であるため、中間クラスを辞書に置き換えることで抑制することはできません。コンテナクラスをそのフィールドで置き換える(たとえば、「m_epoch」変数を「m_modules」で渡す)代替案は、暗黙のオブジェクトを作成しているため(他にないものはありえない)、単に悪いです。利益。

私の好み言語(Python)では、特定のロジック(基本的な取得と設定を除く)がオブジェクトに属さない場合、私の経験則ではオブジェクトを作成しません。しかし、あなたの制約を考えると、あなたが持っている構成階層は可能な限り最高のデザインだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.