クラスファイルとインターフェイスファイルを整理するにはどうすればよいですか?


17

OK ..すべての議論の後、私が扱っている具体的な例をより良く反映するために質問を少し変更しています。


私は2つのクラスModelOneとを持っていますModelTwo。これらのクラスは同様のタイプの機能を実行しますが、互いに無関係です。しかし、私はCommonFunc両方ModelOneで実装されているいくつかのパブリック機能を含む3番目のクラスをModelTwo持っていDRYます。2つのモデルはModelMainクラス内でインスタンス化されます(それ自体はより高いレベルなどでインスタンス化されますが、このレベルで停止しています)。

私が使用しているIoCコンテナはMicrosoft Unityです。私はそれの専門家であるふりはしませんが、インターフェイスのクラスとコンテナをクラスに登録し、具体的なクラスが必要な場合は、特定のインターフェイスに一致するオブジェクトをIoCコンテナに尋ねることです。これは、Unityからインスタンス化するすべてのオブジェクトに対して、一致するインターフェイスが必要であることを意味します。各クラスは異なる(重複しない)機能を実行するため、これは、インターフェイスとクラス1の比率が1:1であることを意味します。しかし、それは私が書くすべてのクラスのためにインターフェースを慎重に書いているという意味ではありません。

したがって、コード的には2になります。

public interface ICommonFunc 
{ 
}

public interface IModelOne 
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelTwo
{ 
   ICommonFunc Common { get; } 
   .. 
}

public interface IModelMain 
{ 
  IModelOne One { get; } 
  IModelTwo Two { get; } 
  ..
}

public class CommonFunc : ICommonFunc { .. }

public class ModelOne : IModelOne { .. }

public class ModelTwo : IModelTwo { .. }

public class ModelMain : IModelMain { .. }

問題は、ソリューションを整理する方法についてです。クラスとインターフェイスを一緒に保つ必要がありますか?または、クラスとインターフェイスを一緒に保持する必要がありますか?例えば:

オプション1- クラス名別に整理

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-Main
          |   |
          |   |-IModelMain.cs
          |   |-ModelMain.cs
          |
          |-One
          |   |
          |   |-IModelOne.cs
          |   |-ModelOne.cs
          |
          |-Two
              |
              |-IModelTwo.cs
              |-ModelTwo.cs
              |

オプション2-機能別に編成(主に)

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Common
          |   |
          |   |-CommonFunc.cs
          |   |-ICommonFunc.cs
          |
          |-IModelMain.cs
          |-IModelOne.cs
          |-IModelTwo.cs
          |-ModelMain.cs
          |-ModelOne.cs
          |-ModelTwo.cs
          |

オプション3-インターフェースと実装の分離

MySolution
  |
  |-MyProject
      |
      |-Interfaces
      |   |
      |   |-Models
      |   |   |
      |       |-Common
      |       |   |-ICommonFunc.cs
      |       |
      |       |-IModelMain.cs
      |       |-IModelOne.cs
      |       |-IModelTwo.cs
      |
      |-Classes
          | 
          |-Models
          |   |
              |-Common
              |   |-CommonFunc.cs
              |
              |-ModelMain.cs
              |-ModelOne.cs
              |-ModelTwo.cs
              |

オプション4-機能の例をさらに取り上げる

MySolution
  |
  |-MyProject
  |   |
      |-Models
      |   |
          |-Components
          |   |
          |   |-Common
          |   |   |
          |   |   |-CommonFunc.cs
          |   |   |-ICommonFunc.cs
          |   |   
          |   |-IModelOne.cs
          |   |-IModelTwo.cs
          |   |-ModelOne.cs
          |   |-ModelTwo.cs
          |
          |-IModelMain.cs
          |-ModelMain.cs
          |

パスのクラス名のために、オプション1が嫌いです。私は1に傾向していますとしてではなく、:ので、私のIoCの選択/使用方法の1つの比率を(そしてそれは議論の余地もあります)これは、ファイル間の関係を見ることに利点があります。

オプション2は魅力的ですが、今ModelMainではサブモデルとサブモデルの間の水を汚しています。

オプション3は、インターフェース定義を実装から分離する働きをしますが、今ではパス名にこれらの人為的な中断があります。

オプション4。コンポーネントを親モデルから分離するために、オプション2を使用して調整しました。

一方を他方よりも優先する正当な理由はありますか?または私が見逃した他の潜在的なレイアウトはありますか?


1.フランクは、1:1の比率を使用すると、C ++の.hファイルと.cppファイルに似ているとコメントしました。彼がどこから来たのか知っています。Unityについての私の理解は、このコーナーに私を連れて行くように思えますが、あなたがまたProgram to an interface 別の日の議論であるという格言に従っているなら、それから抜け出す方法すら分かりません。

2.各オブジェクトコンストラクターの詳細は省略しました。これは、必要に応じてIoCコンテナがオブジェクトを注入する場所です。


1
あー 1対1のインターフェイス/クラスの比率があるというにおいがします。どのIoCコンテナーを使用していますか?Ninjectは、1:1の比率を必要としないメカニズムを提供します。
ラバーダック

1
@RubberDuck FWIW Unityを使用しています。私はその専門家であると主張していませんが、私のクラスが単一の責任でうまく設計されている場合、どうすればほぼ1:1の比率にならないのですか?
ピーターM

IBaseが必要ですか、それとも抽象化できますか?既にIBaseを実装しているのに、なぜIDerivedOneがあるのですか?派生ではなく、IBaseに依存する必要があります。Unityについては知りませんが、他のIoCコンテナーを使用すると、「コンテキスト依存」インジェクションを実行できます。基本的にClient1必要な場合IBase、それは提供しDerived1ます。がClient2必要なIBase場合、IoCはを提供しDerived2ます。
ラバーダック

1
ベースが抽象的である場合、それを使用する理由はありませんinterface。An interfaceは、実際にはすべての仮想メンバーを持つ単なる抽象クラスです。
ラバーダック

1
ラバーダックは正しいです。余分なインターフェイスは単純に迷惑です。
フランクヒルマン

回答:


4

インターフェースは抽象的に基本クラスに似ているため、基本クラスに使用するのと同じロジックを使用します。インターフェイスを実装するクラスは、インターフェイスと密接に関連しています。

「Base Classes」というディレクトリを好むとは思いません。ほとんどの開発者はそれも「インターフェース」と呼ばれるディレクトリも望まないでしょう。C#では、ディレクトリもデフォルトで名前空間であるため、二重に混乱します。

最善のアプローチは、別のライブラリにクラス/インターフェイスを配置する必要がある場合にクラス/インターフェイスを分割し、同様の方法で名前空間/ディレクトリを整理する方法を考えることです。.netフレームワークの設計ガイドラインには、役立つネームスペースの提案があります。


私はあなたが提供したリンクにある程度精通していますが、それがファイル編成にどのように関係するのかわかりません。VSはデフォルトで初期ネームスペースのパス名を使用しますが、これは任意の選択であることを知っています。また、コードの「サンプル」とレイアウトの可能性を更新しました。
ピーターM

@PeterMどのIDEを使用しているかはわかりませんが、Visual Studioは、たとえばクラスを追加するときにディレクトリ名を使用して名前空間宣言を自動的に生成します。つまり、ディレクトリ名と名前空間名に違いがある場合でも、そのように作業する方が苦痛です。そのため、ほとんどの人はそうしません。
フランクヒルマン

VSを使用しています。そして、はい、痛みを知っています。Visual Source Safeファイルレイアウトの思い出を呼び戻します。
ピーターM

1
@PeterMクラス対比率の1:1インターフェイスに関して。一部のツールではこれが必要です。私はこれをツールの欠陥と考えています-.netには、そのようなツールでこのような制限を必要としない十分なリフレクション機能があります。
フランクヒルマン

1

もちろん、2番目のアプローチを取ります。複雑なプロジェクトでは、さらにいくつかのフォルダー/名前空間を使用します。つまり、具体的な実装からインターフェイスを切り離します。

別のプロジェクトでは、インターフェイスの定義を知る必要がありますが、特にIoCコンテナを使用する場合は、それを実装する具体的なクラスを知る必要はまったくありません。したがって、これらの他のプロジェクトは、実装プロジェクトではなく、インターフェイスプロジェクトを参照するだけで済みます。これにより、参照を低く保つことができ、循環参照の問題を防ぐことができます。


私は私のコード例を改訂し、いくつかのより多くのオプションが追加されました
ピーター・M

1

設計に関する他の質問と同様に、最初に行うことは、ユーザーを決定することです。彼らはあなたの組織をどのように使用しますか?

彼らはあなたのクラスを使用するコーダーですか?次に、インターフェイスをコードから分離するのが最適です。

彼らはあなたのコードのメンテナーですか?その後、インターフェースとクラスをまとめておくことが最善かもしれません。

座っていくつかのユースケースを作成します。その後、あなたの前に最高の組織が現れるかもしれません。


-2

インターフェイスを別のライブラリに保存する方が良いと思います。第一に、この種の設計は依存性を高めます。そのため、これらのインターフェイスの実装は別のプログラミング言語で行うことができます。

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