Хорошо ... после всего обсуждения я немного изменяю свой вопрос, чтобы лучше отразить конкретный пример, с которым я имею дело.
У меня есть два класса ModelOneи ModelTwo, эти классы выполняют похожий тип функциональности, но не связаны друг с другом. Тем не менее, у меня есть третий класс, CommonFuncкоторый содержит некоторые общедоступные функциональные возможности, которые реализованы в обоих ModelOneи ModelTwoбыли учтены в соответствии с DRY. Две модели создаются внутри 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: 1 из-за моего выбора / использования IoC (и это может быть спорным), у этого есть преимущества в видении отношений между файлами.
Вариант 2 привлекателен для меня, но теперь я замутил воды между ModelMainи суб-моделями.
Вариант 3 работает, чтобы отделить определение интерфейса от реализации, но теперь у меня есть эти искусственные разрывы в именах путей.
Вариант 4. Я взял вариант 2 и настроил его, чтобы отделить компоненты от родительской модели.
Есть ли веская причина для предпочтения одного над другим? Или какие-то другие потенциальные макеты, которые я пропустил?
1. Фрэнк отметил, что соотношение 1: 1 возвращает нас к дням .h и .cpp файлов C ++. Я знаю, откуда он. Мое понимание Единства, похоже, ставит меня в этот угол, но я также не уверен даже, как выйти из него, если вы также следуете пословице Program to an interface Но это обсуждение для другого дня.
2. Я опустил детали каждого конструктора объектов. Здесь контейнер IoC вводит объекты по мере необходимости.
Client1нужно IBase, это обеспечивает Derived1. Когда Client2необходимо IBase, IoC предоставляет Derived2.
interfaceдля этого. Это interfaceдействительно просто абстрактный класс со всеми виртуальными членами.