OK .. dopo tutta la discussione sto cambiando leggermente la mia domanda per riflettere meglio un esempio concreto di cui mi sto occupando.
Ho due classi ModelOne
e ModelTwo
, Queste classi eseguono un tipo simile di funzionalità ma non sono correlate tra loro. Tuttavia ho una terza classe CommonFunc
che contiene alcune funzionalità pubbliche che sono implementate in entrambi ModelOne
e ModelTwo
che sono state fattorizzate come da DRY
. I due modelli sono istanziati all'interno della ModelMain
classe (che a sua volta è istanziata a un livello superiore ecc. - Ma mi sto fermando a questo livello).
Il contenitore IoC che sto usando è Microsoft Unity . Non pretendo di esserne un esperto, ma la mia comprensione è che registri una tupla di interfaccia e classe con il contenitore e quando vuoi una classe concreta chiedi al contenitore IoC qualunque oggetto corrisponda a un'interfaccia specifica. Ciò implica che per ogni oggetto che voglio creare un'istanza da Unity, ci deve essere un'interfaccia corrispondente. Poiché ciascuna delle mie classi esegue funzionalità diverse (e non sovrapposte), ciò significa che esiste un rapporto 1: 1 tra interfaccia e classe 1 . Tuttavia, ciò non significa che sto scrivendo con disinvoltura un'interfaccia per ogni classe che scrivo.
Quindi, per quanto riguarda il codice, finisco con 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 { .. }
La domanda è su come organizzare la mia soluzione. Devo tenere la classe e l'interfaccia insieme? O dovrei tenere insieme classi e interfacce? PER ESEMPIO:
Opzione 1 : organizzata in base al nome della classe
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-Main
| |
| |-IModelMain.cs
| |-ModelMain.cs
|
|-One
| |
| |-IModelOne.cs
| |-ModelOne.cs
|
|-Two
|
|-IModelTwo.cs
|-ModelTwo.cs
|
Opzione 2 : organizzata per funzionalità (principalmente)
MySolution
|
|-MyProject
| |
|-Models
| |
|-Common
| |
| |-CommonFunc.cs
| |-ICommonFunc.cs
|
|-IModelMain.cs
|-IModelOne.cs
|-IModelTwo.cs
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Opzione 3 - Interfaccia e implementazione separate
MySolution
|
|-MyProject
|
|-Interfaces
| |
| |-Models
| | |
| |-Common
| | |-ICommonFunc.cs
| |
| |-IModelMain.cs
| |-IModelOne.cs
| |-IModelTwo.cs
|
|-Classes
|
|-Models
| |
|-Common
| |-CommonFunc.cs
|
|-ModelMain.cs
|-ModelOne.cs
|-ModelTwo.cs
|
Opzione 4 : approfondire l'esempio di funzionalità
MySolution
|
|-MyProject
| |
|-Models
| |
|-Components
| |
| |-Common
| | |
| | |-CommonFunc.cs
| | |-ICommonFunc.cs
| |
| |-IModelOne.cs
| |-IModelTwo.cs
| |-ModelOne.cs
| |-ModelTwo.cs
|
|-IModelMain.cs
|-ModelMain.cs
|
Non mi piace l'opzione 1 a causa del nome della classe nel percorso. Ma poiché sto tendendo al rapporto 1: 1 a causa della mia scelta / utilizzo dell'IoC (e questo potrebbe essere discutibile), questo ha dei vantaggi nel vedere la relazione tra i file.
L'opzione 2 mi piace, ma ora ho confuso le acque tra il ModelMain
e il sottomodello.
L'opzione 3 funziona per separare la definizione dell'interfaccia dall'implementazione, ma ora ho queste interruzioni artificiali nei nomi dei percorsi.
Opzione 4. Ho preso l'opzione 2 e l'ho modificata per separare i componenti dal modello principale.
C'è una buona ragione per preferire l'una all'altra? O eventuali altri layout che mi sono perso?
1. Frank ha commentato che il rapporto 1: 1 riporta ai giorni C ++ di file .h e .cpp. So da dove viene. La mia comprensione di Unity sembra mettermi in questo angolo, ma non sono nemmeno sicuro di come uscirne se stai anche seguendo il proverbio di Program to an interface
Ma questa è una discussione per un altro giorno.
2. Ho tralasciato i dettagli di ciascun costruttore di oggetti. Qui è dove il contenitore IoC inietta oggetti come richiesto.
Client1
bisogno di un IBase
, fornisce un Derived1
. Quando è Client2
necessario IBase
, l'IoC fornisce a Derived2
.
interface
. An interface
è davvero solo una classe astratta con tutti i membri virtuali.