階層化ソフトウェアアーキテクチャの同じ層のオブジェクト間に依存関係があることは問題ですか?


12

n層アーキテクチャと依存性注入を備えた中規模のソフトウェアを考えると、ある層に属するオブジェクトは下位層のオブジェクトに依存することができますが、上位層のオブジェクトには決して依存しないと言えます。

しかし、同じレイヤーの他のオブジェクトに依存するオブジェクトについてどう考えるべきかわかりません。

例として、3つのレイヤーと画像内のオブジェクトのような複数のオブジェクトを持つアプリケーションを想定してみましょう。明らかに、トップダウンの依存関係(緑の矢印)は問題ありませんが、ボトムアップ(赤い矢印)は問題ありませんが、同じレイヤー内の依存関係(黄色の矢印)はどうでしょうか。

ここに画像の説明を入力してください

循環依存関係を除き、発生する可能性のある他の問題と、この場合に階層化アーキテクチャがどれだけ違反されているかについて興味があります。


あなたはサイクルを持っていない場合、あなたはhorysontalリンクを持っている層に分割は、レイヤ間の依存関係のみを持つサブ層に存在する
max630

回答:


10

はい、ある層のオブジェクトは相互に直接の依存関係持つことできます。時には周期的なものもあります。方向を

ただし、そのような依存関係を任意の方法で持つ必要があるという意味ではありません。実際には、レイヤーが表すもの、システムの大きさ、部品の責任に依存します。「階層化アーキテクチャ」は曖昧な用語であり、異なる種類のシステムで実際に意味するものには大きなバリエーションがあることに注意してください。

たとえば、データベースレイヤー、ビジネスレイヤー、ユーザーインターフェイス(UI)レイヤーを備えた「水平に階層化されたシステム」があるとします。UIレイヤーに少なくとも数十の異なるダイアログクラスが含まれているとしましょう。

ダイアログクラスが他のダイアログクラスに直接依存しないデザインを選択できます。「メインダイアログ」と「サブダイアログ」が存在し、「メイン」ダイアログから「サブ」ダイアログへの直接の依存関係のみがあるデザインを選択できます。または、既存のUIクラスが同じレイヤーの他のUIクラスを使用/再利用できるデザインを好む場合があります。

これらはすべて設計上の選択肢であり、構築するシステムのタイプに応じて多かれ少なかれ賢明ですが、システムの「階層化」を無効にするものはありません。


UIの例を続けて、内部依存関係を持つことの長所と短所は何ですか?再利用が容易になり、循環依存関係が導入されることがわかります。これは、使用するDIメソッドによっては問題になる場合があります。他に何か?
bracco23

@ bracco23:「内部」依存関係を持つことの長所と短所は、任意の依存関係を持つことの短所の長所と同じです。「短所」は、特に他のコンポーネントから分離して、コンポーネントの再利用とテストを難しくすることです。長所は、明示的な依存関係により、結束を必要とするものの使用、理解、管理、およびテストが容易になることです。
Doc Brown

14

レイヤーに属するオブジェクトは、下位レイヤーのオブジェクトに依存できると言ってもいい

正直に言うと、あなたはそれに満足すべきではないと思います。些細なシステム以外のものを扱うときは、すべてのレイヤーが他のレイヤーからの抽象化のみに依存するようにします。より低く、より高く。

したがって、たとえば、にObj 1依存しないでくださいObj 3。たとえば、依存関係を持ち、IObj 3その抽象化のどの実装が実行時に動作するかを通知する必要があります。指示を行うことは、それらの依存関係をマップすることが仕事であるため、どのレベルとも無関係でなければなりません。IoCコンテナー、たとえばmain純粋なDIを使用するなどによって呼び出されるカスタムコードである可能性があります。または、プッシュ時にサービスロケーターになることもあります。とにかく、その事がマッピングを提供するまで、レイヤー間に依存関係は存在しません。

しかし、同じレイヤーの他のオブジェクトに依存するオブジェクトについてどう考えるべきかわかりません。

これが直接的な依存関係持つべき唯一の時間であると私は主張します。これはそのレイヤーの内部動作の一部であり、他のレイヤーに影響を与えることなく変更できます。したがって、有害なカップリングではありません。


答えてくれてありがとう。はい、レイヤーはオブジェクトではなくインターフェイスを公開する必要があります。それは知っていますが、単純にするために省略しました。
bracco23

4

これを実際に見てみましょう

ここに画像の説明を入力してください

Obj 3Obj 4存在することがわかった。だから何?なぜ私たちは気にしますか?

DIPによると

「高レベルのモジュールは低レベルのモジュールに依存すべきではありません。両方とも抽象化に依存すべきです。」

しかし、すべてのオブジェクトが抽象化されているわけではありませんか?

DIPも言う

「抽象化は詳細に依存すべきではありません。詳細は抽象化に依存すべきです。」

わかりましたが、オブジェクトが適切にカプセル化されている場合、詳細は隠されませんか?

すべてのオブジェクトにキーワードインターフェースが必要であると盲目的に主張したい人もいます。私は彼らの一人ではありません。私は盲目的に、今すぐそれらを使用しない場合、後でそれらのような何かを必要とすることに対処する計画が必要だと主張したいのです。

コードがリリースごとに完全にリファクタリング可能な場合、必要に応じて後でインターフェースを抽出できます。再コンパイルしたくないコードを公開していて、インターフェースを介して会話したい場合は、計画が必要になります。

Obj 3Obj 4存在することを知っています。しかし、具体的かObj 3どうかObj 4はわかりますか?

これがまさにここにあるので、newどこにでも広がらないのはとてもいいことです。もしObj 3あれば知らないObj 4あなたは、後にこっそりとなった場合、それは、その後、それを作成していない可能性があるため、コンクリートであるObj 4抽象クラスにObj 3気にしないでしょう。

それができれば、Obj 4ずっと完全に抽象化されています。最初からそれらの間のインターフェースを作成する唯一のことは、誰かが偶然にそれを与えるコードを誤って追加しないという保証ですObj 4。保護されたコンストラクターはそのリスクを軽減できますが、それは別の質問につながります。

Obj 3とObj 4は同じパッケージにありますか?

多くの場合、オブジェクトは何らかの方法(パッケージ、名前空間など)でグループ化されます。グループ化すると、グループ全体ではなくグループ内の影響が発生する可能性が高くなります。

機能別にグループ化するのが好きです。場合Obj 3Obj 4同じグループとレイヤーである、それはあなたが1を公表していないだけで、他の1を変更する必要ながら、それをリファクタリングする必要がありますことを非常に低いです。つまり、これらのオブジェクトは、明確なニーズを持つ前にそれらの間に抽象化を配置することによる恩恵を受けにくい可能性があります。

グループの境界を越える場合は、どちらの側のオブジェクトも独立して変化させることをお勧めします。

単純ですが、残念ながらJavaとC#の両方がこれを複雑にする不幸な選択をしているはずです。

C#では、すべてのキーワードインターフェイスにIプレフィックスを付けることが伝統的です。これにより、クライアントはキーワードインターフェースと通信していることを知る必要があります。それはリファクタリング計画を台無しにします。

Javaでは、より良い命名パターンを使用するのが伝統です。FooImple implements Fooただし、Javaはキーワードインターフェイスを異なるバイナリにコンパイルするため、これはソースコードレベルでのみ役立ちます。つまりFoo、1文字のコードを変更する必要のない、具体的なクライアントから抽象的なクライアントにリファクタリングする場合、再コンパイルする必要があります。

これらの特定の言語のバグが、本当に必要になるまで人々が正式な抽象化を延期できないようにするものです。使用している言語を言わなかったが、単にこれらの問題を持たない言語があることを理解した。

あなたが使用している言語を言わなかったので、あなたはそれがどこでもキーワードインターフェースになるだろうと決める前にあなたの言語と状況を注意深く分析することを強くお勧めします。

ここでは、YAGNIの原則が重要な役割を果たします。しかし、「足で自分自身を撃つことを困難にしてください」。


0

上記の答えに加えて、さまざまな観点からそれを見るのに役立つと思います。

たとえば、依存関係ルールの観点から。DRは、Robert C. Martinが有名なClean Architectureで提案したルールです。

それは言います

ソースコードの依存関係は、より高いレベルのポリシーに向けて、内側のみを指している必要があります。

より高いレベルのポリシーによって、彼はより高いレベルの抽象化を意味します。具体的なクラスやデータ構造とは対照的に、インスタンスインターフェイスや抽象クラスなど、実装の詳細でリークするコンポーネント。

問題は、ルールがレイヤー間の依存関係に制限されないことです。コードが属する場所やレイヤーに関係なく、コード間の依存関係のみを示します。

だから、同じレイヤーの要素間に依存関係を持つことに本質的に問題はありません。ただし、依存関係は、安定した依存関係の原則で伝えるために実装できます。

別の観点はSRPです。

デカップリングは、有害な依存関係を解消し、依存関係の反転(IoC)などのベストプラクティスで伝えるための方法です。ただし、変更理由を共有する要素は、変更理由が同じ要素が同時に(非常に可能性が高い)変更され、同時に展開されるため、分離の理由を与えません。それは間のケースだ場合Obj3Obj4、その後、もう一度、本質的には何の問題もありません。

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