Pensate eredità + polimorfismo
Ecco po 'di codice, farò punti dopo .. .
public abstract class WeirdPerson() {
public virtual void DoThis() {
// base/default implementation as desired
}
public virtual void DoThat() { // ditto }
public abstract void GoWildAndCrazy;
}
public class WeirdChild : WeirdPerson {
public override void DoThis() { // weird child behavior}
// etc.
}
public class WeirdDad : WeirdPerson {
// override and add methods as needed.
}
public class Version_1
{
public string Name { get; protected set; }
public int Age { get; protected set; }
public WeirdPerson WeirdFamilyMember { get; protected set; }
public MysteriousDad Mysterious { get; protected set; }
public Version_1 (WeirdChild child, string name, int age, MysteriousDad Dad) {
}
}
public class Version_2 : Version_1 {
public Version_2 (WeirdDad dad, string name, int age, MysteriousDad grandfather) : base (dad, name, age, grandfather) {}
}
WeirdPerson
- un concetto più generale che definisce le cose di base per tutti i sottotipi.
- Sotto-tipo otterrà "fissa" le cose come
Name
-eredità
- Sotto-tipo può
override
comportamento predefinito (metodi) - polimorfismo
- ora non abbiamo roba divertente guardare:
public class WeirdDad : WeirdChild
- Costruttori
Version_1
, Version_2
costruttori obbligano il client a fornire il sottotipo WeirdPerson
corretto.
- Il cliente deve darci tutti i materiali richiesti.
- Possiamo convalidare/validare in modo incrociato gli argomenti in entrata.
- Non abbiamo bisogno di nessun stinkin'
interface
abstract
classe ci permette di avere un comportamento di default (metodi) e stato di default (proprietà)
public
metodi e le proprietà di qualsiasi classe è un interfaccia in senso generale. Non è necessario avere (parola chiave C#) interface
per seguire il principio codice per interfacce non implementazione
abstract
metodi di implementazione di sottoclasse. appena. piace. un.interface
.
new
- ATTENZIONE. Il metodo che nasconde separa la catena di ereditarietà in quel punto. Se ereditiamo da questa classe, non stiamo ereditando l'implementazione del metodo della classe base originale.
- Liskov è felice.
Ulteriori Rifattorizzare
Fai la gerarchia Version
parallelo la WeirdPerson
gerarchia
Assumendo questo si inserisce nel vostro disegno. Penso che tra un anno sarai contento di averlo fatto.
public abstract class Version_X {
// all the original properties here.
// virtual and abstract methods as needed
// LOOK! standard-issue constructor!
protected Version_X (WeirdPerson person, ...) { // common validation, etc. }
}
public class Version_1 : Version_X {
public Version_1(WeirdChild child, ...) : base (child, ...) {}
}
public class Version_2 : Version_X {
public Version_2 (WeirdDad dad, ...) {}
}
Edit - Motivato da comment discussion with DVK
Il principio della conoscenza almeno dice un cliente non avrebbe dovuto conoscere i dettagli interni di utilizzare una classe. Avere bisogno di sapere come comporre il corretto Version
e Weird
è una violazione, si potrebbe obiettare.
Supponiamo che un costruttore predefinito, per Visitor
diciamo, sia necessario altrove nel progetto generale. Ciò significa che un cliente può controllare la composizione Version
/Weird
.
Astrazione - accoppiamento lento - è nelle classi abstract
. Le classi concrete devono necessariamente essere correttamente composte in modo che il "forte accoppiamento" sia inerente alla creazione di oggetti concreti (i parametri del costrutto di tipo esplicito), ma l'accoppiamento libero sottostante consente la flessibilità desiderata.
public enum WeirdFamily { Child, Dad, Mother, TheThing }
public static class AdamsFamilyFactory() {
public static Version_X Create (WeirdFamily familyMember) {
switch (familyMember) {
case Dad:
return BuildAdamsDad();
// . . .
}
}
}
public static class MunstersFactory() { // Munsters implementation }
// client code
List<Version_X> AdamsFamily = new List<Version_X>();
Version_X Pugsly = AdamsFamilyFactory.Create(WeirdFamily.Child);
AdamsFamily.Add(Pugsly);
List<Version_X> Munsters= new List<Version_X>();
Version_X Eddie= MunstersFactory.Create(WeirdFamily.Child);
Munsters.Add(Eddie);
DoTheMonsterMash(Munsters);
DoTheMonsterMash(AdamsFamily);
public void DoTheMonsterMash(List<Version_X> someWeirdFamily {
foreach (var member in someWeirdFamily)
member.GoWildAndCrazy();
}
Perché non si astraggono proprietà papere strane e misteriose per restituire la base più astratta possibile con la versione 1? La modifica che si sta pianificando di eseguire con v 2 interromperà il codice client. Figlio e papà sono entrambi "Persone", quindi, restituiscilo Person, rendilo virtuale, e poi puoi scavalcare il tuo getter strano senza frenare i clienti perché weirdchild è anche una persona –
Quello che stai cercando si chiama "nascondendo", tu probabilmente sta ricevendo un avvertimento sul compilatore quando compilate il codice sopra, ma vi nascondete esplicitamente dichiarando la proprietà "new", ovvero: public new WeirdChild Weird {get; impostato; } 'Tuttavia si noti che questo può essere fonte di confusione quando si opera con l'oggetto' Version_2' dichiarato come 'Version_1', come' Version_1 child = new Version_2(); ',' child.Wierd' opererà sulla classe base, non sul derivato uno. –
Mi dispiace ma la tua domanda non è chiara. Non vuoi vedere la proprietà 'Weird' dalla classe base sull'istanza dell'oggetto' Version_2' e vuoi nasconderla? –