依存性注入:すべてのパーツを保持するCarクラスを作成する必要がありますか?


10

私のC ++アプリケーションには多くの車があり、すべてRaceTrackに含まれています。

各車は何百ものパーツで構成されています。各部分は他の部分に依存しています。

私はDIとMark Seemannの本で多くのSO質問を読みましたが、すべての自動車部品は相互に依存し、この部品のスープは自動車なので、自動車部品を保持するためだけにCarクラスを定義するべきではないようです。私は正しいですか?

したがって、すべてのレーシングカーをRaceTrackに配置すると、自動車の実体はなく、トラック上で互いにレーシングし合うことに依存する多くの自動車部品がありますか?私は正しいですか?

編集:

車のロジックをプログラミングしている場合は車のクラスが必要であることは明らかだったので、長い間私は車のクラスをプログラミングしていました。しかし、DIでは、それは私にはそれほど明白ではありません。Carクラスが定義されていない場合にCarクラスを作成しないのは、DIの慣用句ですか?

つまり、運転用にSteeringWheelを、ピットクルー用にホイールにBoltsAndNutsを配置し、車全体を表すインスタンスがなくても、他のあらゆる種類の面白いインターフェースを配置しても問題ありませんか?

回答:


24

誰かがレーストラックに座っている車のパーツの束は何がいいですか?

あなたの車のクラスのすべてが車の部品を保持している場合、それは部品のウェットバッグと同じくらい便利です。

使用法

ドライバーとして私が欲しいのは私がコントロールできるものです。それは私がスピードを求めるときに反応します。それはそのレールのように処理します。それは10セントで止まることができます。

私が欲しいのは、使える車のクラスです。キャブレターがどのように機能するかを考える必要なく物事を行うために私が言うことができること。アクセルペダルについて考えてみます。それらがどのように接続されているかは私が心配することではありません。それは抽象化です。

依存性注入

依存性注入はそれとは何の関係もありません。私が車を運転しているとき、私はそれがどのように構築されたかについては考えていません。それが機能する限り、私は彼らがそれをどのように組み合わせるかを気にしません。

いいえ、DIを使用すると、ピットクルーがすぐにタイヤを交換して、コース上で雨が降り始めたときに、より良いタイヤに交換できます。完全に別の車に飛び込むことなくそれができるのは素晴らしいことです。

DIは、実際には原則に従うことです。つまり、構造と分離して使用します。

時速90マイルで新しいタイヤを取り付けることができる車はクールに聞こえるかもしれませんが、タイヤが取り付けられており、それを装着してレースに勝つことはできないと思います。

DIは、ピットクルーがパーツにアクセスできるようにパーツを取り付けることです。new同じ場所で使用して動作をプログラムすると、キャブレターを所定の位置に溶接しているようになります。確かにアセチレントーチはそれを取り除くことができますが、最初にナットとボルトの使用を検討してください。

それがDIです。確かに、newあなたがそれを欲することに気づくとすぐに何かを始めるほど簡単ではありません。代わりに、車の組み立て方法を知っている別のコードを記述する必要があります。ただし、後で変更するのが簡単になります。そして、それはあなたがあなたと一緒にトラックの周りに自動車組立工場を引きずる必要がないことを意味します。

建設

どこかで、タイヤがグッドイヤーかどうかを知る必要があります。それでは、どこに車の建設コードを置くのですか?車でない場合、ピットクルーは?いいえ、トラック?いいえ。これらすべてに動作コードがあります。レース中に実行する必要があるコード。車の組み立ては、行動コードから削除された場所でレース前に行われる必要があります。Mark Seemansは、この場所を「Composition Root」と呼んでいました。ほとんどの人はそれをメインと呼んでいます。

シンプルなパターンです。主に、オブジェクトグラフを作成してから、オブジェクトグラフ内の1つのオブジェクトに対して1つの動作メソッドを呼び出します。それでおしまい。これは、構造と動作が一緒になっている必要がある唯一の場所です。

これは、構築がすべてメインで順次配置される手続き型コードの山でなければならないという意味ではありません。言語のすべてのツールを自由に使用して作成できます。行動と混同しないでください。

これを言語で行い、DIフレームワークやIoCコンテナを使用しないことを純粋なDIと呼びます。それは非常にうまく機能します。長い間持っています。以前は、参照渡しと呼んでいました。

DIツール

DIツールが購入するのは、構造の詳細を別の言語(xml、jsonなど)に移動して、構造と動作の分離を強制することです。仲間のプログラマーが信頼newすべきではないときに使用しないと信頼できない場合は、魅力的です。

欠点は、DIツールの詳細をコードベース全体に行き渡らせたくなることです。独自仕様のアノテーションをコードベースに感染させることがある。彼らが提供する例は確かにこれを奨励しています。このツールは、ジョブをJavaプログラミングジョブとして宣伝するだけでなく、Java / Springプログラミングジョブとして宣伝するまでは、言語スペースに移動する傾向があります。

設計原則

車のロジックをプログラミングしている場合は車のクラスが必要であることは明らかだったので、長い間私は車のクラスをプログラミングしていました。しかし、DIでは、それは私にはそれほど明白ではありません。Carクラスが定義されていない場合にCarクラスを作成しないのは、DIの慣用句ですか?

抽象化について学び、クラスが必要であると判断する方法を変更していると思います。それは良い。しかし、それはDIの問題ではありません。DIは、車のクラスが必要かどうかを判断するのに役立ちません。DIは、タイヤがグッドイヤータイヤである場合に、車が気付かないようにするのに役立ちます。DIを使用すると、トラックが日本製かどうかをトラックが把握できなくなります。

ソフトウェア設計における最も基本的な質問の1つは、「何について何を知っているか」です。これが、UMLダイアグラムで示される主なものです。あなたが到達している何かを新しくするとき、それはあなたが今結びついている具体的なものへのインターフェースです。車はタイヤがグッドイヤーであることを知る必要があります。ミシュランがあなたを後援したいなら、どれがうんざりするでしょう。

これを回避することは、依存関係の逆転の原則に従って呼び出されます。正式には、(carクラスのような)高レベルモジュールは(GoodyearTireクラスのような)低レベルモジュールに直接依存すべきではありません。抽象化に依存する必要があります(Tireインターフェースなど)。

これを回避する方法は、制御の反転と呼ばれます。ここでは、制御の流れを変更することに重点が置かれています。タイヤは車を動かしますか、それとも車はタイヤを動かしますか?これを正しい方法で考えると、車とタイヤを静的に結合することができなくなります。DIは、制御の反転を追跡する1つの特定の方法です。

車のクラスが必要かどうかはわかりません。「車のロジック」をプログラミングしている場合は、どこにでも分散させるのではなく、それを保持する場所が1つあると便利です。車の構築ロジックは車の動作ロジックと同じであると考えて騙されないでください。そのため、すべて同じ場所に住む必要があります。ただし、車のロールが定義されていない場合は、どちらも必要ありません。必要に応じて、トラックの周りでオートバイをレースします。

つまり、運転用にSteeringWheelを、ピットクルー用にホイールにBoltsAndNutsを配置し、車全体を表すインスタンスがなくても、他のあらゆる種類の面白いインターフェースを配置しても問題ありませんか?

DIまたはDIなし。車全体を表すインスタンスがあれば問題ありませんが、必要がない場合、そのインスタンスは直接知りたいものではありません。車の抽象化を教えてください。使用するときに、それがガス、ディーゼル、または電気で動くかどうか気にする必要はありません。それは私がそれを構築または維持しているときに私が気にする必要がある唯一のものです。carを使用するコードがそれがどのように機能するかを知っていたり、気にする必要がない場合は、すばらしいことです。「知りません。知りたくありません。」


コードを表すためにそれらを使用する質問に車とピットクルーのメタファーを使用しなかった場合は、すばらしいでしょう。しかし、それでも、良い答えです。
S.TarıkÇetin2017

6
そして、私はいつもコントロールの逆転はあなたが左に操縦するときだと思っていましたが、車は右折します...
mkrieger1

CandiedOrange、意味のあるインターフェースと明確に定義された責任がない場合、Carクラスはありませんか?そして、私のプロジェクトにはCar.hはありません。そして、私のコードを調べて、それが自動車部品のeショップまたはガレージ管理アプリケーションなのかと思っている同僚はいますか?:)
アントンペトロフ2017

@AntonPetrov「それがアヒルのように見え、アヒルのように鳴るが、バッテリーが必要な場合、おそらく間違った抽象化を持っている」。適切な名前は非常に重要であり、考えるのは難しいかもしれませんが、明確に定義された責任と意味のあるインターフェースを反映するように変更して、驚くような結果にならないようにする必要があります。名前を読んで、インターフェイスを見て、「私が期待していたことはほとんどそれだ」と思ったら、良い名前が付けられています。
candied_orange 2017

15

すべての車の部品は互いに依存し、この部品のスープは車なので、車の部品を保持するためだけにCarクラスを定義するべきではないようです。私は正しいですか?

番号。

依存性注入のポイントは、依存性を阻止することではありません。まったく逆です。

依存性注入は問題です:車はどこから部品入手しますか?それらはどこでどのように作成され、車はどのように参照されますか?

単純に、車はを呼び出すことで部品自体を作成しますnew。これは簡単で簡単ですが、非常に柔軟性がありません。車はパーツを作成するために必要なすべてを知っている必要があり、パーツが異なる2台の車が必要な場合は、そのロジックも車に組み込まれる必要があります。

依存性注入により、そのすべてのロジックが車から取り出され、構成コンポーネントに入れられます。これにより、すべてのパーツが作成され、参照が配線されます。完全に設定れた依存関係が車に注入されます-そしてお互いに。


1
最後に、dependency injectionコンセプトの正しい説明。
anatly techtonik 2017

1
「素朴な」アプローチのより一般的なシステムは、車が新しいと呼ぶのではなく、車クラスのユーザーがそのパーツをそのプロパティに割り当て、その間車クラスが不確定な状態。DIは、クラスの有効性を機械的に保証する手段を提供します。
whatsisname 2017

2
@whatsisname DIを使用して、無効で半分初期化されたオブジェクトを簡単に作成できます。検証はDIの責任ではありません。不変でもありません。DIは、有効で不変のオブジェクトを構築する仕事を引き受けることができます。DIは、これらのオブジェクトが構築および使用される唯一の方法であることを強制する方法はありません。オブジェクトはこれを強制する必要があります。
candied_orange 2017

@CandiedOrange:簡単に任意のテクニックを使用して中途半端なものを作ることができるので、何ですか?コンストラクターで依存関係を要求し、それらを不変にすることは特効薬ではありませんが、それでも多くの一般的な悪い状況を防ぐ非常に便利な方法です。
whatsisname 2017

0

したがって、すべてのレーシングカーをRaceTrackに配置すると、自動車の実体はなく、トラック上で互いにレーシングし合うことに依存する多くの自動車部品がありますか?私は正しいですか?

上手。はいといいえ。車のエンティティはまだ有効です。そして、自動車はその部品の合計以上のものです。ドライバーも必要です(当面の間)。多くの場合、レースカーには車のメーカーとモデルは言うまでもなく、名前もあります。

はい、車は基本的にパーツのコンテナですが、何かを大きくするのは、このパッケージングとパーツの協力です。つまり、車です。

本当にそうです。車は単なる金属とプラスチックのバッグではありません。それは機械です。

この場合、依存性注入は過剰ではありません。何かを車を構築する必要があります。これは、ファクトリクラスまたはビルダーオブジェクトになります。車はそれ自体を構築する方法を知らないはずです。


2
ファクトリやビルダーオブジェクトなしでDIを作成できます。単純なコンストラクタパラメータは、多くの状況で機能する有効なメソッドです。
whatsisname
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.