web-dev-qa-db-ja.com

SOLID原則とコード構造

最近の就職の面接で、私は [〜#〜] solid [〜#〜] -についての質問に答えることができませんでした。それは本当に私を悩ませます。私は2、3日分の調査を行いましたが、まだ満足のいく要約を作成していません。

インタビューの質問は:

SOLID原則に厳密に従っていると私が言った.Netプロジェクトを見るとしたら、プロジェクトとコード構造の観点から何を期待できますか?

私は少し悩みましたが、実際には質問に答えず、爆撃しました。

この質問にどのように対処できたでしょうか?

154
S-Unit

S =単一責任の原則

したがって、よく整理されたフォルダ/ファイル構造とオブジェクト階層が表示されると思います。機能の各クラス/部分は、その機能が非常に明白であることを示す必要があり、そのタスクを実行するロジックのみを含む必要があります。

数千行のコードを含む巨大なマネージャークラスを見た場合、それは単一の責任が守られていなかったことを示しています。

O =開閉原理

これは基本的に、既存の機能への影響を最小限に抑える、または変更を必要としない新しいクラスを通じて新しい機能を追加するという考えです。

オブジェクトの継承、サブタイピング、インターフェース、抽象クラスを多く使用して、機能の設計と実際の実装を分離し、他のバージョンに影響を与えずに他のバージョンを一緒に実装できるようになると思います元の。

L =リスコフ置換原理

これは、サブタイプを親タイプとして扱う機能に関係しています。適切に継承されたオブジェクト階層を実装している場合、これはC#のボックスから出てきます。

一般的なオブジェクトをベースタイプとして扱い、サブタイプ自体をインスタンス化して操作するのではなく、ベース/抽象クラスでメソッドを呼び出すコードが見られると思います。

I =インターフェース分離の原則

これはSRPに似ています。基本的に、機能のより小さなサブセットをインターフェースとして定義し、それらを使用してシステムを分離したままにします(たとえば、FileManagerはファイルI/Oを処理する単一の責任を持つかもしれませんが、特定のメソッド定義を含むIFileReaderおよびIFileWriterを実装できますファイルの読み取りおよび書き込み用)。

D =依存関係の逆転の原則

再び、これはシステムを分離した状態に保つことに関係しています。おそらく、UnityNinjectなどのソリューション、またはAutoFacServiceLocatorなどのServiceLocatorシステムで使用されている.NET Dependency Injectionライブラリの使用に目を光らせているでしょう。

191
Eoin Campbell

多くの小さなクラスと、依存性注入を伴うインターフェースがいたるところにあります。おそらく大きなプロジェクトでは、IoCフレームワークを使用して、これらすべての小さなオブジェクトのライフタイムを構築および管理するのに役立つでしょう。 https://stackoverflow.com/questions/21288/which-net-dependency-injection-frameworks-are-worth-looking-into を参照してください

SOLIDの原則に厳密に従っている大きな.NETプロジェクトは、必ずしもすべての人と協力するのに優れたコードベースを意味するわけではありません。インタビュアーが誰であるかによっては、 SOLIDの意味を理解し、かつ/または独断的に設計原則に従っていることを確認すること。

確かに、あなたがしっかりしているためには、あなたは従う必要があります:

[〜#〜] s [〜#〜]責任の原則が1つであるため、1つのことだけを行う小さなクラスが多数あります。

[〜#〜] o [〜#〜]ペンで閉じた原理。これは通常、.NETでは依存関係の注入で実装され、Iも必要ですと下のD ...

[〜#〜] l [〜#〜]iskovの置換の原則は、c#でワンライナーで説明することはおそらく不可能です。幸いにも、それに対処する他の質問があります。 https://stackoverflow.com/questions/4428725/can-you-explain-liskov-substitution-principle-with-a-good-c-sharp-example

[〜#〜] i [〜#〜]インターフェース分離原理は、オープン/クローズの原理と連携して機能します。文字通り従うのであれば、少数の「大きな」インターフェースではなく、多数の非常に小さなインターフェースを優先することを意味します。

[〜#〜] d [〜#〜]依存関係の反転の原則高レベルのクラスは低レベルのクラスに依存してはならず、どちらも抽象化に依存している必要があります。

17
Paolo Falabella

私が日々の仕事でSOLIDを支持しているショップのコードベースに見られると期待するいくつかの基本的なこと:

  • 多くの小さなコードファイル-.NETのベストプラクティスとしてファイルごとに1つのクラス、および小さなモジュラークラス構造を奨励する単一責任の原則により、それぞれが1つの小さな集中クラスを含む多くのファイルが表示されると予想します。
  • 多くのアダプターパターンと複合パターン-ある目的のために開発された依存関係のプラグインをわずかに合理化するために、多くのアダプターパターン(別のインターフェイスの機能に「パススルー」することによって1つのインターフェイスを実装するクラス)の使用を期待しますその機能性も必要とされるさまざまな場所。使用するファイル名を指定する手段を公開するようにインターフェイスを更新すると、コンソールロガーをファイルロガーに置き換えるだけの簡単な更新で、LSP/ISP/DIPに違反します。代わりに、ファイルロガークラスは追加のメンバーを公開し、アダプターは新しいものを非表示にすることでファイルロガーをコンソールロガーのように見せるため、これらすべてをスナップするオブジェクトだけが違いを知る必要があります。

    同様に、クラスが既存のものと同様のインターフェースの依存関係を追加する必要がある場合、オブジェクト(OCP)の変更を回避するために、通常の答えは複合/戦略パターン(依存関係インターフェースを実装し、他の複数のクラスを消費するクラス)を実装することですそのインターフェースの実装。さまざまな量のロジックを使用して、クラスが1つ、一部、またはすべての実装に呼び出しを渡すことができます)。

  • たくさんのインターフェースとABC-DIPは必ず抽象化が存在することを必要とし、ISPはこれらを狭い範囲に限定することを推奨しています。したがって、インターフェースと抽象基本クラスがルールであり、コードベースの共有依存関係機能をカバーするには、それらの多くが必要になります。厳密なSOLIDはeverythingを注入する必要がありますが、どこかに作成する必要があることは明らかなので、GUIフォームが1つの親フォームの子としてのみ作成される場合は上記の親に対して何らかのアクションを実行する場合、親から直接コードから子フォームを更新する必要はありません。通常、そのコードを独自のメソッドにするだけなので、同じフォームの2つのアクションがウィンドウを開いた場合は、方法。
  • 多くのプロジェクト-これらすべての目的は、変更の範囲を制限することです。変更には、再コンパイルの必要性が含まれます(これは比較的簡単な作業ですが、モバイル環境への更新プログラムの展開など、プロセッサや帯域幅が重要な多くの操作では依然として重要です)。プロジェクト内の1つのファイルを再構築する必要がある場合、すべてのファイルが再構築されます。つまり、実装と同じライブラリにインターフェイスを配置すると、要点が失われます。インターフェイス定義自体も再コンパイルするため、インターフェイスの実装を変更する場合は、すべての使用法を再コンパイルする必要があります。これにより、使用法では、結果のバイナリの新しい場所をポイントする必要があります。したがって、インターフェースを使用法から分離するand実装を維持しながら、一般的な使用領域によってそれらをさらに分離することは、典型的なベストプラクティスです。
  • 「ギャングオブフォー」という用語に多くの注意を払った-1994年の本で特定されたデザインパターンデザインパターン SOLIDが求める一口サイズのモジュール式コードデザインを強調するたとえば、依存関係の逆転の原則とオープン/クローズの原則は、その本で識別されているほとんどのパターンの中心にあります。したがって、SOLIDギャングオブフォーの本の用語も採用するための原則、および「AbcFactory」、「XyzRepository」、「DefToXyzAdapter」、「A1Command」など、それらの線に沿った機能に従ってクラスに名前を付ける.
  • 一般的なリポジトリ-一般的に理解されているISP、DIP、SRPに準拠して、リポジトリはSOLID設計でほぼどこにでもあります。検索/永続化メカニズムの知識。DAOパターンとは対照的に、これを行うコードを1か所に配置します(たとえば、Invoiceデータクラスがある場合、ハイドレートされたInvoiceDAOも生成されます)そのタイプのオブジェクトなど、コードベース/スキーマ内のすべてのデータオブジェクト/テーブル)。
  • IoCコンテナ-実際に依存関係の注入の大部分を行うためにIoCフレームワークを使用していないため、これを追加するのをためらっています。これはすぐに、すべてをコンテナに投入し、それを揺さぶって、注入されたファクトリメソッドを介して必要な垂直に水和された依存関係を注ぎ出すGod Objectアンチパターンになります。構造がかなりモノリシックになり、登録情報を含むプロジェクトが「流暢」であれば、ソリューション内のすべてについてすべてを知る必要があることに気づくまで、素晴らしいですね。 lot変更の理由です。流暢ではない場合(構成ファイルを使用した遅延登録)、プログラムの主要部分は「マジックストリング」に依存し、まったく異なるワームを実行できます。
13
KeithS

SOLIDの「O」が「役に立たず、よく理解されていない」という Jon Skeetの議論 でそれらをそらし、Alistair Cockburnの「保護されたバリエーション」とJoshについて話してもらいます。 Blochの「継承のための設計、またはそれを禁止する」。

スキートの記事の短い要約(元のブログ投稿を読まないで彼の名前を落とすことはお勧めしませんが!):

  • ほとんどの人は、「オープン-クローズド原則」の「オープン」と「クローズド」が何を意味するのかを知っていても、彼らがそう思っているとは知りません。
  • 一般的な解釈は次のとおりです。
    • モジュールは常に実装継承を通じて拡張する必要がある、または
    • 元のモジュールのソースコードは変更できません。
  • OCPの根本的な意図、およびBertrand Meyerによるオリジナルの公式化は問題ありません。
    • モジュールには、クライアントが依存できる明確に定義されたインターフェース(「インターフェース」の技術的な意味ではない)が必要ですbut
    • それらのインターフェースを壊すことなく、彼らができることを拡張することが可能であるべきです。
  • しかし、「オープン」と「クローズド」という言葉は、たとえニースの発音可能な頭字語になったとしても、問題を混乱させるだけです。

OPは、「この質問にどのように対処できたでしょうか?」面接を行うシニアエンジニアとして、私は箇条書きのリストからガタガタできる人よりも、さまざまなコードデザインスタイルの長所と短所についてインテリジェントに話すことができる候補者に計り知れないほど興味があります。

別の良い答えは、「まあ、それは彼らがそれをどれだけよく理解しているかに依存します。もし彼らが知っているすべてがSOLID流行語である場合、継承の乱用、依存性注入の乱用を期待しますフレームワーク、100万の小さなインターフェース。いずれも製品管理との通信に使用されるドメイン語彙を反映していません...」

10
David Moles

これには、さまざまな時間で答えることができる方法がいくつかあるでしょう。しかし、これは「SOLIDの意味を知っていますか?」」の方に沿っていると思います。したがって、この質問に答えることは、ポイントに到達し、プロジェクトに関してそれを説明することになるでしょう。

したがって、次のように表示されます。

  • クラスには単一の責任があります(たとえば、顧客のデータアクセスクラスは顧客データベースから顧客データのみを取得します)。
  • クラスは、既存の動作に影響を与えずに簡単に拡張できます。追加の機能を追加するために、プロパティやその他のメソッドを変更する必要はありません。
  • 派生クラスは基本クラスの代わりに使用でき、それらの基本クラスを使用する関数は、それらを処理するために基本クラスをより特定のタイプにアンラップする必要はありません。
  • インターフェイスは小さく、理解しやすいです。クラスがインターフェースを使用する場合、タスクを実行するためにいくつかのメソッドに依存する必要はありません。
  • コードは、高レベルの実装が特定の低レベルの実装に具体的に依存しないように十分に抽象化されています。高レベルのコードに影響を与えることなく、低レベルの実装を切り替えることができるはずです。たとえば、アプリケーションの残りの部分に影響を与えずに、WebサービスベースのSQLデータアクセスレイヤーに切り替えることができます。
6
villecoder

これは素晴らしい質問ですが、面接は難しい質問だと思います。

SOLIDの原則は、クラスとインターフェース、およびそれらの相互関係を実際に管理します。

この質問は、実際にはfilesに関連するものであり、必ずしもクラスではありません。

簡単な観察または私が与える答えは、一般に、インターフェースのみを保持するファイルが表示されることであり、多くの場合、慣習として、それらは大文字のIで始まるということです。さらに、ファイルにはコード(特にモジュール、アプリケーション、またはライブラリ内)が重複しておらず、そのコードはモジュール、アプリケーション、またはライブラリ間の特定の境界を越えて慎重に共有されます。

Robert Martinは、このトピックについて Designing Objected Oriented C++ Applications using the Booch Method のC++の領域で説明しています(上のセクションを参照)凝集性、閉鎖性、再利用性)および Clean Code

4
J. Polfer