Хорошо ... после всего обсуждения я немного изменяю свой вопрос, чтобы лучше отразить конкретный пример, с которым я имею дело.
У меня есть два класса 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
действительно просто абстрактный класс со всеми виртуальными членами.