Perché l'ereditarietà è definita solo in fase di compilazione?

7

Ho trovato questa affermazione dai "Modelli di design" della banda dei quattro particolarmente strana; per alcuni contesti, gli autori stanno confrontando l'ereditarietà con la composizione come meccanismi di riutilizzo [p. 19]:

"...you can't change the implementations inherited from parent classes at run-time, because inheritance is defined at compile-time."

Continuano a dire sulla composizione:

"Object composition is defined dynamically at run-time through objects acquiring references to other objects."

Non sono sicuro del perché questa distinzione di fase sia importante. Ho familiarità con la compilazione e l'ereditarietà ma lavoro come sviluppatore JavaScript, quindi forse mi manca qualcosa di fondamentale.

    
posta gwg 21.01.2014 - 19:29
fonte

3 risposte

8

Alcuni linguaggi sono abbastanza statici e consentono solo la specifica della relazione di ereditarietà tra due classi al momento della definizione di tali classi. Per C ++, il tempo di definizione è praticamente uguale al tempo di compilazione. (È leggermente diverso in Java e C #, ma non molto.) Altri linguaggi consentono una riconfigurazione molto più dinamica della relazione tra classi (e oggetti di classe in Javascript) tra loro; alcuni consentono di modificare la classe di un oggetto esistente o di modificare la superclasse di una classe. (Questo può causare un totale caos logico, ma può anche modellare abbastanza bene i nasties del mondo reale.)

Ma è importante contrapporre questo alla composizione, dove la relazione tra un oggetto e l'altro non è definita dalla loro relazione di classe (cioè, il loro tipo ) ma piuttosto dai riferimenti che ognuno ha in relazione con l'altro. La composizione generale è un metodo molto potente e onnipresente di organizzazione degli oggetti: quando un oggetto ha bisogno di sapere qualcosa su un altro, ha un riferimento a quell'altro oggetto e invoca metodi su di esso quando necessario. Non appena inizi a cercare questo pattern super-fondamentale , lo troverai assolutamente ovunque; l'unico modo per evitarlo è mettere tutto in un oggetto, il che sarebbe enormemente stupido! (C'è anche una composizione / aggregazione UML più rigida, ma non è quello di cui parla il libro GoF.)

Una delle cose della relazione di composizione è che gli oggetti particolari non hanno bisogno di essere strettamente legati l'uno all'altro. Lo schema degli oggetti concreti è molto flessibile, anche in linguaggi molto statici come il C ++. (C'è un lato positivo nell'avere cose molto statiche: è possibile analizzare il codice più da vicino e - almeno potenzialmente - emettere un codice migliore con meno overhead). Per riassumere, Javascript, come con molti altri linguaggi dinamici, può far finta che non usi affatto la compilazione; solo finzione, ovviamente, ma il modello linguistico fondamentale non richiede la trasformazione in un formato intermedio fisso (ad es. un "eseguibile binario su disco"). Questa compilazione viene eseguita in fase di esecuzione e può essere facilmente ripristinata se le cose cambiano troppo. (La cosa affascinante è che un buon lavoro di compilazione può essere fatto, anche partendo da una base molto dinamica ...)

Alcuni pattern GoF hanno davvero senso solo nel contesto di un linguaggio in cui le cose sono abbastanza statiche. Va bene; significa semplicemente che non tutte le forze che influenzano il modello sono necessariamente elencate. Uno dei punti chiave sullo studio dei modelli è che ci aiuta a essere consapevoli di queste importanti differenze e avvertimenti. (Gli altri schemi sono più universali. Tieni gli occhi aperti per quelli.)

    
risposta data 21.01.2014 - 22:47
fonte
2

Consideriamo un linguaggio strongmente tipizzato come C #. Qui definiresti l'ereditarietà come questa:

class BaseClass
{
    public string SomeMethod()
    {
        return "Hello";
    }
}

class DerivedClass : BaseClass  // Inherits BaseClass
{
    public string AdditionalMethod()
    {
        return "World";
    }
}

Utilizzo:

  var d = new DerivedClass();
  Console.WriteLine(d.SomeMethod()); // --> Hello
  Console.WriteLine(d.AdditionalMethod()); // --> World

La classe DerivedClass eredita il metodo SomeMethod da BaseClass . Questo fatto è definito al momento della compilazione. A volte viene usato il termine "design time". L'ultimo termine chiarisce che l'ereditarietà è già definita nel codice dal programmatore.

Al contrario, vediamo come funziona la composizione

interface IReturnsString
{
    string GetString();
}

class ComposedClass
{                                                          
    private IReturnsString _a, _b;

    public ComposedClass(IReturnsString a, IReturnsString b) // Constructor
    {
        _a = a;
        _b = b;
    }

    public string SomeMethodA()
    {
        return _a.GetString();
    }

    public string SomeMethodB()
    {
        return _b.GetString();
    }

    public void ChangeBehavior()
    {
        _a = new ClassC(); // ClassC is supposed to implement IReturnsString.
    }
}

In fase di esecuzione è possibile passare diverse implementazioni alla classe composta. La classe composta potrebbe anche scegliere di cambiare il suo comportamento in fase di runtime.

var x = new ComposedClass(new ClassA(), new ClassB());
Console.WriteLine(x.SomeMethodA()); // Prints something

x.ChangeBehavior();
Console.WriteLine(x.SomeMethodA()); // Prints something else

var y = new ComposedClass(new ClassD(), new ClassE());
// y behaves in a different way than x
    
risposta data 21.01.2014 - 22:37
fonte
1

In Javascript, apparentemente non c'è molta differenza, perché non esiste una compilazione. Da quello che ho letto, ciò che viene comunemente chiamato ereditarietà in JS è solo la creazione di una catena prototipo tra diversi oggetti.
Ma in linguaggi come C #, è possibile creare una gerarchia di ereditarietà in fase di compilazione attraverso classi che si ereditano l'una dall'altra, ma è anche possibile modificare il comportamento degli oggetti in fase di esecuzione attraverso modelli come il modello di strategia.

    
risposta data 21.01.2014 - 19:42
fonte

Leggi altre domande sui tag