2016-07-10 17 views
6

Ho un problema con l'utilizzo della giusta catena di ereditarietà senza perdere buone parti del principio di DRY.Due diverse catene di ereditarietà senza rompere il principio di DRY

Data la seguente struttura:

  • astratto classe A è la mia base per tutte le classi
  • classe astratta B: A è la mia base per tutte le classi che possono avere funzioni speciali (reso disponibile attraverso B)

Ora, ho bisogno di avere due nuove classi che condividono le stesse caratteristiche. Ma uno è di tipo A mentre l'altro è di tipo B. (Questo non può essere modificato!) Entrambe le classi dovrebbero avere un metodo SetSize().

Quindi alla fine ci sarebbe la classe C: A e D: B, entrambi con lo stesso metodo SetSize.

Domanda: Come si crea un livello intermedio di classe base in modo che il metodo SetSize() venga dichiarato/implementato una sola volta (DRY)? Immagino qualcosa sull'utilizzo di interfacce o alcune classi di helper statiche per implementare la logica di SetSize()?

Esistono modelli o migliori pratiche per ottenere questo comportamento?

+2

Correlati - [Preferisci composizione su ereditarietà] (http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance) –

+0

Il comportamento di 'SetSize' sarà lo stesso per tutte le implementazioni? (sia per le classi di tipo A che B, come hai menzionato 'dry')? – Yogi

+0

@Yogi Il metodo sarà esattamente lo stesso per entrambe le implementazioni. Ecco perché sto cercando un modo per averlo in un unico punto – KingKerosin

risposta

2

Non è possibile farlo tramite l'ereditarietà in C# perché non supporta l'ereditarietà multipla; lo strumento della lingua che si dà per questo scenario è interfacce:

public interface 
{  
    void SetSize(Size size); 
} 

public SizableA: A, ISizable { ... } 
public SizableB: B, ISizable { ... } 

Anche tenere a mente che l'ereditarietà deve essere utilizzato quando i tipi nella catena di ereditarietà hanno un è un rapporto (un Cat è un Animal, un B è un A, ecc.) Mentre le interfacce sono preferite quando le classi completamente indipendenti hanno un comportamento comune molto specifico; IEquatable, IComparable, IDisposable, ecc. Il tuo comportamento SetSize sembra adattarsi meglio in quest'ultima categoria in quanto non sembra essere una funzionalità specifica per A o B.

Ora, se entrambi SizableA e SizableB dovrebbero condividere la stessa implementazione del SetSize allora la soluzione migliore è quella di utilizzare la composizione o semplicemente delegare funzionalità:

public interface ISizable 
{ 
    void SetSize(Size size, ISetSizeProvider provider); //Alternatively inject provider in SizableA and SizableB's constructor to get composition. 
} 
0

Fare una classe astratta includono SetSize() metodo e proprietà comuni delle classi A e B. Quindi le classi A e B ereditano la classe astratta.

Problemi correlati