OK ..すべての議論の後で、私が扱っている具体的な例をよりよく反映するために、質問を少し変更しています。
私は2つのクラスModelOne
とModelTwo
を持っています。これらのクラスは同様のタイプの機能を実行しますが、互いに無関係です。ただし、CommonFunc
とModelOne
の両方に実装され、ModelTwo
に従って除外されたいくつかのパブリック機能を含む3番目のクラス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は嫌いです。しかし、私はIoCの選択/使用法(およびは議論の余地があるかもしれない)のため、1:1の比率になる傾向があるため、これにはファイル間の関係を確認する上で利点があります。
オプション2は魅力的ですが、ModelMain
とサブモデルの間の水を濁らせました。
オプション3は、インターフェース定義を実装から分離するように機能しますが、パス名にこれらの人為的な区切りがあります。
オプション4。オプション2を採用し、コンポーネントを親モデルから分離するために微調整しました。
どちらか一方を優先する理由はありますか?または私が見逃した他の潜在的なレイアウト?
1.フランクは、1:1の比率が.hおよび.cppファイルのC++日を思い出させるとコメントしました。私は彼がどこから来たのか知っています。 Unityについての私の理解は私をこのコーナーに引き入れているようですが、あなたがProgram to an interface
しかし、それは別の日の議論です。
2.各オブジェクトコンストラクタの詳細は省略しました。これは、IoCコンテナが必要に応じてオブジェクトを注入する場所です。
インターフェイスは基本的に基本クラスに似ているため、基本クラスに使用するのと同じロジックを使用します。インターフェイスを実装するクラスは、インターフェイスと密接に関連しています。
「基本クラス」と呼ばれるディレクトリを好むとは思いません。ほとんどの開発者はそれを望んでおらず、「インターフェース」と呼ばれるディレクトリも望まないでしょう。 C#では、ディレクトリはデフォルトで名前空間でもあるため、混乱を招きます。
最善のアプローチは、いくつかを別のライブラリーに入れる必要がある場合にクラス/インターフェースを分割し、同様の方法で名前空間/ディレクトリーを編成する方法を考えることです。 .netフレームワークのデザインガイドラインには 名前空間の提案 があり、参考になることがあります。
もちろん、2番目のアプローチを採用します。もちろん、複雑なプロジェクトでは、いくつかのフォルダー/名前空間を使用します。それは、具体的な実装からインターフェースを切り離すことを意味します。
別のプロジェクトでは、インターフェースの定義を知る必要があるかもしれませんが、それを実装する具体的なクラスを知る必要はまったくありません。特に、IoCコンテナーを使用する場合はそうです。したがって、これらの他のプロジェクトは、実装プロジェクトではなく、インターフェースプロジェクトのみを参照する必要があります。これにより、参照を低く抑え、循環参照の問題を防ぐことができます。
いつものデザインの質問と同様に、最初に行うことは、ユーザーが誰であるかを決定することです。彼らはあなたの組織をどのように使用するのですか?
彼らはあなたのクラスを使用するコーダーですか?次に、インターフェイスをコードから分離するのが最善の方法です。
彼らはあなたのコードのメンテナーですか?次に、インターフェイスとクラスを一緒にしておくのが最善です。
座って、いくつかのユースケースを作成します。次に、あなたの前に最高の組織が現れるかもしれません。