OK .. po całej dyskusji zmieniam nieco moje pytanie, aby lepiej odzwierciedlić konkretny przykład, z którym mam do czynienia.
Mam dwie klasy ModelOnei klasy ModelTwote wykonują podobny typ funkcjonalności, ale nie są ze sobą powiązane. Mam jednak trzecią klasę, CommonFuncktóra zawiera pewną funkcjonalność publiczną, która jest zaimplementowana zarówno ModelOnei ModelTwozostała uwzględniona zgodnie z DRY. Dwa modele są tworzone w obrębie ModelMainklasy (która sama tworzy się na wyższym poziomie itp. - ale zatrzymuję się na tym poziomie).
Kontener IoC, którego używam, to Microsoft Unity . Nie udaję, że jestem w tym ekspertem, ale rozumiem, że rejestrujesz krotkę interfejsu i klasy w kontenerze, a kiedy chcesz konkretnej klasy, pytasz kontener IoC o dowolny obiekt pasujący do określonego interfejsu. Oznacza to, że dla każdego obiektu, który chcę utworzyć z Unity, musi istnieć pasujący interfejs. Ponieważ każda z moich klas wykonuje inną (i nie nakładającą się) funkcjonalność, oznacza to, że istnieje stosunek 1: 1 między interfejsem a klasą 1 . Nie oznacza to jednak, że niewolniczo piszę interfejs dla każdej klasy, którą piszę.
Zatem pod względem kodu kończę na 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 { .. }
Pytanie dotyczy tego, jak zorganizować moje rozwiązanie. Czy powinienem trzymać klasę i interfejs razem? Czy powinienem trzymać klasy i interfejsy razem? NA PRZYKŁAD:
Opcja 1 - zorganizowane według nazwy klasy
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-Main
| |
| |-IModelMain.cs
| |-ModelMain.cs
|
|-One
| |
| |-IModelOne.cs
| |-ModelOne.cs
|
|-Two
|
|-IModelTwo.cs
|-ModelTwo.cs
|
Opcja 2 - uporządkowane według funkcjonalności (głównie)
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-IModelMain.cs
|-IModelOne.cs
|-IModelTwo.cs
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Opcja 3 - Interfejs oddzielający i implementacja
MySolution
|
|-MyProject
|
|-Interfaces
| |
| |-Models
| | |
| |-Common
| | |-ICommonFunc.cs
| |
| |-IModelMain.cs
| |-IModelOne.cs
| |-IModelTwo.cs
|
|-Classes
|
|-Models
| |
|-Common
| |-CommonFunc.cs
|
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Opcja 4 - Dalszy przykład funkcjonalności
MySolution
|
|-MyProject
| |
|-Models
| |
|-Components
| |
| |-Common
| | |
| | |-CommonFunc.cs
| | |-ICommonFunc.cs
| |
| |-IModelOne.cs
| |-IModelTwo.cs
| |-ModelOne.cs
| |-ModelTwo.cs
|
|-IModelMain.cs
|-ModelMain.cs
|
Nie podoba mi się opcja 1 z powodu nazwy klasy na ścieżce. Ale ponieważ mam tendencję do stosunku 1: 1 ze względu na mój wybór / użycie IoC (i to może być dyskusyjne), ma to zaletę w widzeniu związku między plikami.
Opcja 2 jest dla mnie atrakcyjna, ale teraz zamazałem wody między podmodelami ModelMaina nimi.
Opcja 3 działa w celu oddzielenia definicji interfejsu od implementacji, ale teraz mam te sztuczne przerwy w nazwach ścieżek.
Opcja 4. Wziąłem opcję 2 i poprawiłem ją, aby oddzielić komponenty od modelu nadrzędnego.
Czy istnieje dobry powód, aby preferować jeden od drugiego? Lub jakieś inne potencjalne układy, które przegapiłem?
1. Frank skomentował, że stosunek 1: 1 nawiązuje do dni C ++ plików .h i .cpp. Wiem skąd on pochodzi. Moje rozumienie Jedności wydaje się wprowadzać mnie w ten kąt, ale nie jestem nawet pewien, jak się z tego wydostać, jeśli również postępujesz zgodnie z przysłowiem Program to an interface Ale to dyskusja na inny dzień.
2. Pominąłem szczegóły każdego konstruktora obiektów. Tutaj kontener IoC wstrzykuje obiekty zgodnie z wymaganiami.
Client1trzeba IBase, zapewnia Derived1. W razie Client2potrzeby IBaseIoC zapewnia Derived2.
interface. interfaceJest naprawdę klasą abstrakcyjną ze wszystkimi członkami wirtualnych.