web-dev-qa-db-ja.com

インスタンスを複数のレイヤーに渡すのは悪い習慣ですか?

私のプログラム設計では、オブジェクトインスタンスを複数のクラスに渡さなければならないことがよくあります。たとえば、オーディオファイルを読み込み、それをプレーヤーに渡すコントローラーがある場合、プレーヤーがそれをplayerRunnableに渡し、playerRunnableが別の場所にもう一度渡します。それを避ける方法を知っています。それともこれでいいですか?

編集:後でファイルをロードできるため、プレーヤーの例は最適ではないかもしれませんが、それ以外の場合は機能しません。

61
Puckl

他の人が述べたように、これは必ずしも悪い習慣ではありませんが、レイヤーの懸念の分離を壊したり、レイヤー間でレイヤー固有のインスタンスを渡したりしていないことに注意する必要があります。例えば:

  • データベースオブジェクトを上位層に渡してはなりません。 DALでDataAdapterを使用してDTOまたはデータセットを作成して渡すのではなく、.NETの DataAdapter クラス、DBアクセスクラスを使用してUIレイヤーに渡すプログラムを見てきました。そのアップ。 DBアクセスはDALのドメインです。
  • もちろん、UIオブジェクトはUIレイヤーに限定する必要があります。繰り返しますが、これは違反しています。ListBoxesに、コンテンツの配列/ DTOの代わりにBLレイヤーに渡されるユーザーデータが入力されており、(私が特に気に入っている)階層データを取得するDALクラスがあります。 DBは、階層的なデータ構造を返すのではなく、TreeViewオブジェクトを作成してデータを入力し、UIに渡して動的にフォームに追加しました。

ただし、渡すインスタンスがDTOまたはエンティティ自体の場合は、おそらく問題ありません。

54

Immutableオブジェクト についてまだ誰も話していないのは興味深いことです。さまざまなレイヤーすべてに不変オブジェクトを渡すことは、各レイヤーに短期間のオブジェクトをたくさん作成するのではなく、実際には良いことだと私は主張します。

Eric Lippertによる不変性についてのすばらしい議論が 彼のブログ にあります。

一方、レイヤー間で可変オブジェクトを渡すことはbad設計であると私は主張します。基本的に、周囲のレイヤーがコードを壊すような方法でレイヤーを変更しないという約束でレイヤーを構築しています。

15
M Afifi

オブジェクトインスタンスの受け渡しは通常行うことです。状態(インスタンス変数など)を保持する必要性を減らし、コードをその実行コンテキストから分離します。

直面する可能性のある1つの問題はリファクタリングであり、呼び出しチェーンの最下部近くにあるメソッドのパラメーター要件の変更に応じて、呼び出しチェーンに沿って複数のメソッドのシグニチャーを変更する必要があります。ただし、リファクタリングに役立つ最新のソフトウェア開発ツールを使用すると軽減できます。

13
dasblinkenlight

マイナーかもしれませんが、この参照をいずれかのレイヤーのどこかに割り当てると、後でぶら下がっている参照やメモリリークが発生する可能性があります。

8
techfoobar

コードのリモート領域で必要なだけの理由でオブジェクトを渡す場合は、 inversion of control と依存性注入のデザインパターンをオプションで適切なIoCコンテナーと共に使用すると、オブジェクトインスタンスの搬送に関する問題をうまく解決できます周り。私は中規模のプロジェクトでそれを使用しており、それを使用せずに大きなサーバーコードを作成することを二度と考えません。

7

一連のレイヤーを介してデータを渡すことは悪いことではありません。レイヤードシステムがレイヤード構造に違反することなく機能できる唯一の方法です。問題がある兆候は、目標を達成するために同じレイヤー内の複数のオブジェクトにデータを渡す場合です。

4
Ryathal

クイックアンサー:オブジェクトのインスタンスを渡す際に何も問題はありません。また、前述のように、すべてのレイヤーでこの参照の割り当てをスキップして、ぶら下がっている参照またはメモリリークを引き起こす可能性がある点が重要です。

私たちのプロジェクトでは、このプラクティスを使用してレイヤー間で DTO(データ転送オブジェクト) を渡します。これは非常に役立つプラクティスです。また、要約情報の場合のように、dtoオブジェクトを再利用して、より複雑なものを1回作成します。

3
Yusubov

私は主にWeb UI開発者ですが、直感的な不快感はインスタンスのパススルーではなく、そのコントローラーを少し手続き的に使用しているという事実のほうが多いように思えます。あなたのコントローラーはこれらすべての詳細を発汗させるべきですか?オーディオを再生するために、他の複数のオブジェクトの名前を参照するのはなぜですか?

OOP=デザインでは、何が常緑樹であり、何が変更される可能性が高いかという観点から考える傾向があります。変更の対象は、あなたが入れようとするものです。より大きなオブジェクトボックスを使用すると、プレーヤーが変更されたり新しいオプションが追加されたりしても一貫したインターフェイスを維持できます。または、オーディオオブジェクトやコンポーネントを卸売りで交換したい場合もあります。

この場合、コントローラーは、オーディオファイルを再生する必要があることを識別し、それを再生するための一貫した/常緑の方法を持つ必要があります。一方、オーディオプレーヤーは、テクノロジーやプラットフォームが変更されたり、新しい選択肢が追加されたりすると、簡単に変更される可能性があります。これらの詳細はすべて、大きな複合オブジェクトであるIMOのインターフェースの下に配置する必要があり、オーディオの再生方法の詳細が変更されたときにコントローラーを書き換える必要はありません。次に、ファイルの場所などの詳細を含むオブジェクトインスタンスを大きなオブジェクトに渡すと、すべての入れ替えは、誰かが愚かなことをする可能性が低い適切なコンテキストの内部で行われます。

したがって、この場合は、オブジェクトインスタンスがトスされてバグを引き起こす可能性があるとは思いません。キャプテンピカードがエンジンルームまで走ってワープコアをオンにし、ブリッジまで戻って座標をプロットし、シールドをオンにした後で「Take」とだけ言うのではなく、「パンチイット」ボタンを押します。 Warp 9で惑星Xに移動します。そうしてください。」そして彼の乗組員に詳細を整理させました。彼がそれをそのように扱うとき、彼はすべての船のレイアウトとすべてがどのように機能するかを知らなくても、艦隊のあらゆる船を船長することができるからです。そして、それは最終的に最大のOOP狙うデザインの勝利、IMOです。

3
Erik Reppen

アプリがそのようなことに敏感である場合、レイテンシの問題が発生する可能性がありますが、それは結局起こる一般的な設計です。

2
James

この問題は、動的スコープ変数(言語に変数がある場合)またはスレッドローカルストレージで解決できます。これらのメカニズムにより、いくつかのカスタム変数をアクティブ化チェーンまたは制御のスレッドに関連付けることができるため、これらの値を他のコードと通信できるようにするためだけに、それらとは関係のないコードにこれらの値を渡す必要がなくなります。それらを必要とします。

2
Kaz

他の回答が指摘したように、これは本質的に貧弱な設計ではありません。入れ子になったクラスとそれらを入れ子にしたクラスの間の密結合を作成できますが、参照を入れ子にして設計に値を提供する場合、結合を緩めることは有効なオプションではない可能性があります。

考えられる解決策の1つは、コントローラークラスのネストされた参照を「フラット化」することです。

ネストされたオブジェクトを介してパラメーターを数回渡す代わりに、ネストされたすべてのオブジェクトへの参照をコントローラークラスで維持できます。

これが正確にどのように実装されるか(またはそれが有効なソリューションでさえあるかどうか)は、次のようなシステムの現在の設計によって異なります。

  • ネストしすぎたオブジェクトのある種のマップを、複雑になりすぎずにコントローラーで維持できますか?
  • パラメータを適切なネストされたオブジェクトに渡すと、ネストされたオブジェクトはパラメータをすぐに認識できますか、それともネストされたオブジェクトを介して渡すときに追加の機能が発生しましたか?
  • 等.

これは、GXTクライアントのMVCデザインパターンで発生した問題です。私たちのGUIコンポーネントには、いくつかのレイヤー用のネストされたGUIコンポーネントが含まれていました。モデルデータが更新されたとき、適切なコンポーネントに到達するまで、いくつかのレイヤーを通過しました。新しいGUIコンポーネントクラスでモデルデータを受け入れる場合は、新しいクラスを含むすべてのGUIコンポーネントのモデルデータを更新するメソッドを作成する必要があるため、GUIコンポーネント間の不要な結合が作成されました。

これを修正するために、ViewクラスでネストされたすべてのGUIコンポーネントへの参照のマップを維持し、モデルデータが更新されるたびに、ビューが更新されたモデルデータを必要なGUIコンポーネントに直接送信できるようにしました。 。各GUIコンポーネントのインスタンスは1つしかなかったため、これはうまくいきました。一部のGUIコンポーネントのインスタンスが複数ある場合は、うまく機能しないため、更新が必要なコピーを特定するのが困難です。

2
David Kaczynski

あなたが説明しているのは Chain Of Responsibility デザインパターンと呼ばれるものです。 Appleは、イベント処理システムにこのパターンを使用しています。

0
user8865