Quando spostare un campo comune in una classe base?


16

Al momento ho due classi derivate Ae B, che hanno entrambe un campo in comune e sto cercando di determinare se dovrebbe andare nella classe base.

Non viene mai referenziato dalla classe base, e dire se in qualche punto lungo la strada viene derivata un'altra classe C, che non ha un _field1, quindi il principio del "meno privilegiato" (o qualcosa) non sarebbe violato se era?

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}

18
Credo che questa domanda non è chiaro perché non ci hai dato la minima idea di che cosa Base, A, B, C, e _field1sono. Questi sono dettagli importanti che non dovrebbero essere esclusi; Penso che dovresti modificare la domanda per parlare di cosa siano.
Tanner Swett,

Sulla base delle risposte vorrei: ricostruire il Veicolo per avere una Sospensione virtuale, quindi Auto e Bicicletta potrebbero avere Ruote e La Barca potrebbe avere Galleggiabilità, che sposta l'astrazione verso l'alto. Trovo che se la mia astrazione porta direttamente a impostazioni specifiche, allora non ho spostato il concetto abbastanza in alto nella catena.
Patrick Hughes,

6
Non utilizzare l'ereditarietà delle classi per evitare la duplicazione del codice. Usalo per ereditare ed estendere il comportamento , cioè il polimorfismo. Sposta un campo comune in una classe base se e solo se è logicamente lo stesso campo, non due informazioni non correlate che condividono lo stesso nome nei rispettivi contesti.
Brandon,

Perché hai una classe base per cominciare?
jpmc26,

Risposte:


34

Tutto dipende dal problema esatto che stai cercando di risolvere.

Considera un esempio concreto: la tua classe base astratta è Vehiclee al momento hai le implementazioni concrete Bicyclee Car. Stai pensando di spostarti numberOfWheelsda Bicyclee Carverso il veicolo. Dovresti farlo? No! Perché non tutti i veicoli hanno le ruote. Puoi già dire che se provi ad aggiungere una Boatclasse, si romperà.

Ora, se la tua classe di base astratta era WheeledVehicleallora è logico avere la numberOfWheelsvariabile membro all'interno.

Devi applicare la stessa logica al tuo problema, perché come puoi vedere, non è una semplice risposta sì o no.


3
Si potrebbe temporaneamente accettare che 0 è un numero valido di Ruote. Tuttavia, alla fine potresti aggiungere un roll()metodo, a quel punto l'idea della sottoclasse sembra presciosa.
user949300

11
Una barca ha 0 ruote. Cosa si rompe?
D Drmmr,

14
@DDrmmr Non è che una barca abbia 0 ruote, ma le ruote non esistono nemmeno come concetto per una barca - quindi i tuoi modelli non dovrebbero permetterlo.
Peter M,

10
Il mio punto è che l'esempio è negativo. Non c'è nulla di concettualmente sbagliato in un veicolo (che sembra essere una barca) affermando che ha 0 ruote.
D Drmmr,

10
Quindi va tutto all'inferno quando devi riporre una barca a remi.
IllusiveBrian

13

Logicamente parlando, oltre a posizionare il campo replicato in sottoclassi e in comune nella classe base, esiste una terza opzione: introdurre una nuova sottoclasse nella gerarchia che ha le proprietà comuni tra le due. @Pete suggerisce questo senza andare completamente lì.

Usando l'esempio di @Pete, introdurremmo una sottoclasse (possibilmente astratta) per il veicolo a ruote che discende dalla classe base originale - mentre le due sottoclassi discendono da essa. Pertanto, la classe base originale non è inquinata con le ruote, tuttavia la comunanza delle ruote è ASCIUTTA (non ripetuta tra le sottoclassi che hanno ruote).

Questo può ovviamente essere eccessivo per i tuoi scopi, ma è supportato dal meccanismo della gerarchia di classi.


In realtà è quello che ho deciso di fare (A e B si sovrappongono principalmente, quindi B deriverà da A).
Samis,

9

Qui interpreterò l'avvocato del diavolo.

In questo momento non dovresti fare nulla .

È ASCIUTTO? No. Ma è meglio avere una piccola duplicazione rispetto a un'astrazione prematura di cui non puoi facilmente tornare indietro in seguito. Il refactor per spostare una proprietà in una classe base comune è semplice. Andare dall'altra parte non lo è. Aspetta e vedi.

Quando prendo questo tipo di decisione, tendo a usare una "regola del 3": una volta che ho ripetuto la stessa cosa in tre posti diversi, e solo allora, prendo in considerazione l'idea di spostarlo su per la catena. NB sei solo a 2.


2
Un'osservazione saggia che, direi, è necessaria per prendere la decisione.
radarbob,

1
Sono per lo più d'accordo, ma "In questo momento" (senza codice aggiuntivo come quello che vediamo) il refactoring in entrambe le direzioni è banale. Ma se esiste un codice aggiuntivo che utilizza il campo, il refactoring in entrambe le direzioni può diventare significativamente più difficile.
Doc Brown,

2

In generale, lo sposterei nella classe base. Non penso che ci sia un obiettivo sì / no, perché qui c'è un compromesso: trasportare campi inutilizzati contro ridurre la complessità.

Preferisco di solito classi base "pesanti" che contengono tutto ciò che potrebbe essere condiviso. Ciò semplifica la serializzazione dei file poiché non sono necessari metodi di serializzazione discendenti in ogni classe derivata. Ma se non hai questo o un problema simile, o forse devi fare tutto il possibile per ridurre l'uso della memoria, allora solo i campi dove ne hai bisogno dovrebbero andare bene.

Una classe "intermediaria" che introduce i campi comuni andrà bene se hai un numero molto limitato di campi. Ma tieni presente che l'approccio può aumentare notevolmente la complessità se hai dozzine di campi utilizzati in combinazioni diverse, portando a molte classi intermedie ognuna delle quali introduce un insieme specifico di campi. Questo può diventare un problema di manutenzione.


Il mio esempio è banale, sebbene sia ancora un codice di produzione. Sostieni una buona argomentazione per "compromettere" la gerarchia con una classe base "pesante", a cui anch'io mi vedrei appoggiato in questo caso.
Samis,

1
@samis: usi le classi denominate "A, B, C" e "Base" con un solo campo e nessun metodo nel codice di produzione? Lo metto in dubbio.
Doc Brown,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.