2012-02-16 14 views
9

Ho cercato informazioni per aiutarmi a risolvere un problema di progettazione che mi confonde. Sono nuovo in situazioni di eredità complicate, quindi la mia soluzione potrebbe essere semplicemente radicata in un design migliore. Ma nel cercare di capire quale dovrebbe essere il mio progetto, continuo a pensare che devo davvero ereditare più di una classe base.Ereditarietà multipla?

Il mio caso specifico riguarda attività e diversi tipi di attività.

A partire dalla Asset ...

Ogni PhysicalDevice è un Asset
Ogni VirtualDevice è un Asset
Ogni Server è un Asset

Ogni PhysicalServer avrebbe bisogno di essere sia un PhysicalDevice e Server
Ogni VirtualServer sarebbe bisogno di essere sia un VirtualDevice e Server
Ogni netdevice è un PhysicalDevice
Ogni StorageArray è un PhysicalDevice

Una soluzione Credo che è quello di duplicare il codice Server per entrambe le PhysicalServers e VirtualServers tuttavia, mi sento come se questo va contro quello che im cercando di fare, che è ereditare.

Devono essere classi separate perché ognuno dei tipi avrà proprietà e metodi. Per esempio, Server avrà OSCaption, memoria, Procs, ecc PhysicalDevice avrà cose come posizione, di serie, Mercante ecc E VirtualDevice avrà un ParentDevice, Stato, ecc VHDLocation

Se il l'ereditarietà è una nave di linea quindi mi imbatto nel problema di non essere in grado di descrivere questi tipi in modo accurato.

Qualcosa che sembra intrigante è Interfacce. Sembra che io possa definire tutte le classi base come interfacce e implementarle nelle mie classi principali secondo necessità. ma, sono semplicemente incerto su quali siano le implicazioni se dovessi farlo.

per esempio, qualcosa come ...PhysicalServer: IAsset: IServer: IPhysical

Sono in acque profonde, quindi sono davvero solo in cerca di suggerimenti o di orientamento.

+0

Si prega di non aggiungere "C#" fino ai confini dei vostri titoli. Ecco a cosa servono i tag. –

risposta

8

Le interfacce sono un modo appropriato per garantire l'integrità del contratto tra i tipi, ma si può finire con un codice duplicato per ogni implementazione.

Lo scenario può prestarsi meglio alla composizione rispetto all'ereditarietà (o una combinazione di questi).

Esempio - Trasmissione + Composizione

public class PhysicalServer : Asset 
{ 
    public PhysicalInfo PhysicalProperties 
    { 
     get; 
     set; 
    } 
} 

public class VirtualServer : Asset 
{ 
    public VirtualInfo VirtualProperties 
    { 
     get; 
     set; 
    } 
} 

Esempio - Composizione Solo

public class VirtualServer 
{ 
    public VirtualInfo VirtualProperties 
    { 
     get; 
     set; 
    } 

    public AssetInfo AssetProperties 
    { 
     get; 
     set; 
    } 
} 

Si potrebbe quindi aggiungere polimorfismo/generici nel mix e creare derivati ​​di tipi per rappresentare più specifica esigenze.

Esempio - Trasmissione + Composizione + genericized membro che eredita da un tipo comune

public class VirtualServer<TVirtualInfo> : Asset 
    where TVirtualInfo : VirtualDeviceInfo 
{ 
    public TVirtualInfo VirtualProperties 
    { 
     get; 
     set; 
    } 
} 

public class VirtualServerInfo : VirtualDeviceInfo 
{ 
    // properties which are specific to virtual servers, not just devices 
} 

Ci sono innumerevoli modi in cui si potrebbe modellare questo fuori, ma armati di interfacce, la composizione, l'ereditarietà e voi generici può venire con un modello di dati efficace.

+2

+1 per la composizione sull'ereditarietà - Trovo che la maggior parte delle situazioni in cui l'ereditarietà stia causando graffi alla testa può essere risolta attraverso un approccio compositivo. –

+0

Per essere chiari, usa le interfacce sulle classi per definire cosa fanno. Quindi componi i membri privati ​​che possono fare il lavoro richiesto dalle interfacce. Sì? – MStodd

+0

@MStodd - sì, se gli oggetti condividono lo stesso contratto (membri e operazioni), quel contratto può (e spesso dovrebbe) essere definito in un'interfaccia. Diversi tipi possono quindi essere trasmessi alla stessa interfaccia e gestiti in modo uniforme. –

1

C# non supporta l'ereditarietà multipla dalle classi (ma supporta più implementazioni di interfacce).

Quello che chiedi non è un'eredità multipla. L'ereditarietà multipla è dove una singola classe ha più di una classe base. Nel tuo esempio ogni classe eredita da uno/zero altre classi. Asset e Server sono le ultime classi base. Quindi non hai problemi a farlo in C#, puoi semplicemente definire la funzionalità comune nel server e poi fare cose diverse in VirtualDevice e Dispositivo fisico.

Tuttavia si finirà con una gerarchia di classi possibilmente complessa e molte persone sarebbero avvocato composizione oltre eredità. Questo è il punto in cui avresti interfacce che definiscono il comportamento e le classi implementano l'interfaccia per dire che fanno qualcosa ma ogni classe può implementare i metodi di interfaccia in modo diverso. Quindi il tuo esempio per le interfacce PhysicalServer può essere incoraggiato.

+0

Vorrei chiarire che Server eredita da Asset. Non sono sicuro che ciò li renda entrambi "classi base di base". La distinzione è importante perché non mi occupo solo di server, ma di tutti i diversi tipi di asset sia virtuali che fisici. Ciò include i server sì, ma anche AttachedStorage, tipi NetworkThing, ecc ... Alla fine voglio essere in grado di avere le classi base necessarie, per consentire sostanzialmente la scalabilità a qualsiasi nuovo tipo di risorsa che potrebbe sorgere. – jwrightmail

+0

Bene, solo Asset è l'ultima classe base e, come suggerito, la composizione dovrebbe generalmente essere preferita con ereditarietà limitata, ove appropriato – kaj

0

Per iniziare ricorda che l'eredità è il risultato ovvio del tipo di problema che hai menzionato. Ogni classe ha più di un comportamento e tutti cadono in questa trappola. Così freddo. Non sei il primo né l'ultimo.

È necessario modificare un po 'il proprio modo di pensare per uscire dalla norma.

È necessario guardarlo dall'angolo di ciò che "cambia" in futuro piuttosto che guardare un tipo gerarchico di diagramma di classe. Un diagramma di classe non può essere gerarchico, ma deve rappresentare "cosa cambia" e cosa "rimane costante". Da quello che vedo, in futuro puoi definire un MobileDevice, VirtualMobileDevice.

Nelle classi attuali sembra che tu abbia proprietà come Vendor, Serial. Questi potrebbero essere necessari anche in MobileDevice giusto? Quindi è necessario modificare il proprio pensiero per pensare effettivamente ai comportamenti anziché alle classi che hanno un senso gerarchico.

Ripensare, si sta andando giù la traccia di più eredità, design molto pericoloso e complesso. Non è la correttezza del tuo processo mentale che è in discussione qui. E 'la tua domanda di codifica di qualcosa e qualcuno in anticipo nel prossimo futuro che lo complica irreparabilmente.

Nessun'ereditarietà di java esiste per questo motivo, per garantire che non si pensi in modo gerarchico.

Pensa alle "fabbriche" (per la creazione), alla strategia (per funzionalità/elaborazione comuni).

Modificato:

Infatti si dovrebbe anche considerare la creazione di strati sotto forma di libreria, in modo che non v'è completa astrazione e il controllo sulle parti principali del processo. Qualsiasi cosa tu intenda fare con la classe Asset/Device dovrebbe essere riassunta in una libreria, che può essere protetta da cambiamenti.

+0

Interessante, e grazie. Sì, il tuo esempio di tipi futuri è perfetto. La possibilità di ridimensionare con i tipi di risorse sarebbe molto vantaggiosa per essere risolta ora piuttosto che dover tornare indietro più tardi e fino all'impianto idraulico principale. ... Behaviors, rifletterò su questo. – jwrightmail

3

Utilizzare miscele.

Per prima cosa decidi qual è la cosa principale che vuoi che il tuo oggetto sia. Nel tuo caso penso che dovrebbe essere server.

public class PhysicalServer : Server

Poi si aggiungono le interfacce per le altre funzionalità.

public class PhysicalServer : Server,IAsset,IVirtualDevice

e si aggiunge metodi di estensione alle interfacce.

public static int WordCount(this IAsset asset) 
{ 
    //do something on the asset 
} 

Ecco un articolo su mixins nel caso in cui la mia risposta è troppo semplice: http://www.zorched.net/2008/01/03/implementing-mixins-with-c-extension-methods/

Problemi correlati