17

依存性注入フレームワーク (春のアノテーション) への最新の追加により、DI 管理コンポーネントを作成するための限界コストは、いくつかの重要な新しいしきい値に達したようです。以前は、Spring に関連するオーバーヘッド (大量の XML と追加の間接参照) がありましたが、依存性注入は、多くのパターンが進むところに行き始めたようです。彼らはボンネットの下に入り、「消えます」。

この結果、多数のコンポーネントに関連する概念的なオーバーヘッドが許容できるようになります。ほとんどのクラスが単一の public メソッドのみを公開するシステムを作成し、これらの断片を狂ったように集約するだけでシステム全体を構築できることは議論の余地があります。私たちの場合、いくつかのことが与えられています。アプリケーションのユーザー インターフェイスには、最上位のサービスを形成するいくつかの機能要件があります。そして、バックエンドシステムが下部を制御します。しかし、これら2つの間では、すべてが手に入る.

私たちの絶え間ない議論は、実際にはなぜ物事をクラスにグループ化するか、そして原則はどうあるべきかということです。いくつかのことは確かです。ファサードのパターンは死んで埋もれています。複数の無関係な機能を含むサービスも、分割される傾向があります。「無関係な機能」は、私がこれまで行ってきたよりもはるかに厳密な意味で解釈されます。

私たちのチームでは、ここで 2 つの一般的な考え方があります。実装の依存関係によってグループ化が制限されます。単一のクラスの機能は、注入されたすべての依存関係のクライアントであることが望ましいです。私たちはDDDプロジェクトであり、他の部分はドメインがグループ化を制限していると考えています(CustomerServiceまたはより細かいCustomerProductService、CustomerOrderService)-注入された依存関係の正規化された使用は重要ではありません.

では、疎結合の DI ユニバースでは、なぜロジックをクラスにグループ化するのでしょうか?

編集: duffymo は、これがプログラミングの関数型スタイルに移行している可能性があると指摘しています。これは状態の問題を引き起こします。関連するアプリケーションの状態の (小さな) 部分を表す "状態" オブジェクトがかなりあります。この状態を正当に必要とするサービスにこれらを挿入します。(通常のドメイン オブジェクトの代わりに「状態」オブジェクトを使用する理由は、Spring が不特定の時間にこれらを構築するためです。これは、Spring がドメイン オブジェクトの実際の作成を管理できるようにするためのわずかな回避策または代替ソリューションであると考えています。より良い解決策があるかもしれません。ここ)。

したがって、たとえば、OrderSystemAccessControlState を必要とするサービスはすべてこれを注入することができ、このデータの範囲はコンシューマーにはすぐにはわかりません。セキュリティ関連の状態の一部は、通常、さまざまなレベルで使用されますが、その間のレベルではまったく見えません。これは機能原則に根本的に違反していると本当に思います。オブジェクト指向の観点からこの概念に適応するのにも苦労しましたが、注入された状態が正確で強く型付けされている限り、その必要性は正当であり、ユースケースは適切です。

4

4 に答える 4

8

優れた OO 設計の最も重要な原則は、疎結合だけでなく、ほとんどの議論で無視される高い凝集性にもとどまりません。

高結束

コンピューター プログラミングでは、結束力とは、1 つのモジュールの責任がどの程度強く関連しているか、または集中しているかを示す尺度です。オブジェクト指向プログラミングに適用されるように、特定のクラスにサービスを提供するメソッドが多くの面で似ている傾向がある場合、そのクラスは凝集度が高いと言われます。凝集性の高いシステムでは、コードの可読性と再利用の可能性が高まり、複雑さは管理しやすくなります。

次の場合、結束力が低下します。

* The functionality embedded in a class, accessed through its methods,
  have little in common.
* Methods carry out many varied activities, often using coarsely-grained or 
  unrelated sets of data.

低結束 (または「弱い結束」) の欠点は次のとおりです。

* Increased difficulty in understanding modules.
* Increased difficulty in maintaining a system, because logical changes in 
  the domain affect multiple modules, and because changes in one module 
  require changes in related modules.
* Increased difficulty in reusing a module because most applications
  won’t need the random set of operations provided by a module.

人々が IoC コンテナーに夢中になると失われることの 1 つは、まとまりが失われ、何かが何をどのように行うかの追跡可能性が、後で自分自身で理解するのが困難になることです。これは、すべての関係が大量の XML 構成によって不明瞭になるためです。ファイル (Spring I'm looking at you) と不適切な名前の実装クラス。

于 2011-03-13T14:54:13.433 に答える
4
  • クラスごとにグループ化するのはなぜですか?また、原則はどうあるべきか?

「グループ化」または「クラス」を強調していますか?

なぜ物事をグループ化するのかという質問がある場合は、2 番目に Medelt の「保守性」を挙げますが、「波及効果の潜在的なコストを削減するため」と言い換えます。

コンポーネント (クラス、ファイルなど) 間の実際の結合ではなく、潜在的な結合、つまり、それらのコンポーネント間のソース コードの依存関係の最大数を考えてみてください。

コンポーネント a - b - c - d - e のチェーンが与えられ、a が b に依存するなどの場合、e を変更するとコンポーネント c が変更される確率は、可能性よりも大きくなり得ないことを示す定理があります。 e を変更すると d が変更されます。また、実際のソフトウェア システムでは、e の変更が c に影響を与える確率は、通常、e の変更が d に影響を与える確率よりも低くなります。

もちろん、それは明らかだと言うかもしれません。しかし、それをさらに明確にすることができます。この例では、d は e に直接依存しており、c は e に (d を介して) 間接的に依存しています。したがって、統計的には、主に直接的な依存関係から形成されたシステムは、主に間接的な依存関係から形成されたシステムよりも大きな波及効果を被ると言えます。

現実の世界では、各波及効果にはお金がかかることを考えると、主に直接的な依存関係で形成されるシステムへの更新の波及効果のコストは、主に直接的な依存関係で形成されるシステムへの更新の波及効果のコストよりも高くなると言えます。間接的な依存関係。

さて、潜在的な結合に戻ります。絶対的なカプセル化コンテキスト (再帰的カプセル化が広く採用されていない Java や C# など) 内では、すべてのコンポーネントが直接的な依存関係または単一の中間コンポーネントとの間接的な依存関係を介して相互に接続されている可能性があることを示すことができます。統計的に、コンポーネント間の直接的な潜在的な結合を最小限に抑えるシステムは、更新による波及効果の潜在的なコストを最小限に抑えます。

そして、直接的および間接的な潜在的結合の間のこの区別をどのように達成するのでしょうか? カプセル化。

カプセル化とは、モデル化されたエンティティに含まれる情報が、そのモデル化されたエンティティによってサポートされているインターフェイスでの対話を通じてのみアクセスできるというプロパティです。これらのインターフェイスを介してアクセスできない情報 (データまたは動作) は、「非表示の情報」と呼ばれます。コンポーネント内の情報隠蔽動作により、外部コンポーネントから間接的に (インターフェースを介して) のみアクセスできることが保証されます。

これには必然的に、ある種のより細かい機能を情報で隠すことができる、ある種のグループ化コンテナが必要です。

これが、私たちが物事を「グループ化」している理由です。

クラスを使用して物事をグループ化する理由については、次のとおりです。

A) クラスは、言語がサポートするカプセル化のメカニズムを提供します。

B) クラスを使用しているだけではありません。カプセル化のために名前空間/パッケージも使用しています。

よろしく、

エド。

于 2009-11-27T06:59:54.423 に答える
3

2つの理由が考えられます。

保守性: いくつかのロジックが連携することを自然に期待するでしょう。データベースなどの特定の外部サービスに対する操作を定義するロジックは、おそらく論理的な方法でグループ化する必要があります。これは、名前空間またはクラスで行うことができます。

状態とアイデンティティ: オブジェクトにはロジックが含まれているだけでなく、状態も保持されます。特定のオブジェクトの状態を操作するインターフェイスの一部であるロジックは、そのオブジェクトで定義する必要があります。オブジェクトはアイデンティティも維持します。問題ドメイン内の 1 つのエンティティをモデル化するオブジェクトは、ソフトウェア内の 1 つのオブジェクトである必要があります。

サイドノードとして: state および identity 引数は、主にドメイン オブジェクトに適用されます。ほとんどのソリューションでは、主にそれらの周りのサービスに IoC コンテナーを使用しました。私のドメイン オブジェクトは通常、プログラム フローの一部として作成および破棄され、通常、これには別のファクトリ オブジェクトを使用します。その後、ファクトリは IoC コンテナによって注入および処理できます。IoC コンテナのラッパーとしてファクトリを作成することに成功しました。このようにして、コンテナーはドメイン オブジェクトの有効期間も処理します。

これは非常に興味深い質問です。過去に実装した方法を振り返ると、インターフェイスとクラスがより小さく、よりきめ細かくなる傾向にあることがわかります。この方法で確実に良くなりました。ただし、最適なソリューションにクラスごとに1つの機能があるとは思いません。これは事実上、OO 言語を関数型言語として使用していることを意味します。関数型言語は非常に強力ですが、2 つのパラダイムを組み合わせるには多くのことが必要です。

于 2009-01-09T12:01:45.047 に答える
2

純粋な DI の完全な宇宙、単一のクラス + メソッドの設計が理想的だと思います。実際には、実現可能性を低くするコストのバランスを取る必要があります。

コスト要因

  • DIのオーバーヘッド。単一のメソッドのすべての基礎および関連する基礎をスピンアップすると、コストがかかります。クラスにグループ化することで、その一部を相殺することができます。
  • スキル - DI は多くの人 (特に私自身) にとって新しいものであるため、DI をより適切に行う方法や、古い/習慣的な設計から抜け出す方法を理解することは困難です。
  • それらを既に持っているブラウン フィールド アプリは、それらと一緒に暮らすのが簡単/安価/迅速であり、将来のグリーン フィールド アプリでこれを心配します

うまくいけば、DI の私の初心者 (はい、私はでっち上げの言葉でいっぱいです) が、これで私を完全に間違ったものにしていないことを願っています。

于 2009-01-09T11:40:01.367 に答える