Idea
Ho avuto questa idea per una funzione linguistica che penso sarebbe utile, qualcuno sa di una lingua che implementa qualcosa di simile?
L'idea è che, oltre all'ereditarietà, una classe può anche usare qualcosa chiamato "imprinting" (per mancanza di termini migliori). Una classe può imprimere una o più classi (non astratte). Quando una classe imprime un'altra classe ottiene tutte le sue proprietà e tutti i suoi metodi. È come se la classe memorizzasse un'istanza della classe impressa e reindirizzasse i suoi metodi / proprietà a essa. Una classe che imprime un'altra classe quindi, per definizione, implementa anche tutte le sue interfacce e la sua classe astratta.
Quindi qual è il punto? Bene, ereditarietà e polimorfismo sono difficili da ottenere. Spesso la composizione dà molta più flessibilità. L'ereditarietà multipla offre un gran numero di problemi diversi senza molti vantaggi (IMO).
Spesso scrivo le classi dell'adattatore (in C #) implementando alcune interfacce e passando i metodi / le proprietà effettive a un oggetto incapsulato. Lo svantaggio di questo approccio è che se l'interfaccia cambia le interruzioni di classe. Devi anche inserire un sacco di codice che non fa altro che passare le cose lungo l'oggetto incapsulato.
Un esempio classico è che hai una classe che implementa IEnumerable o IList e contiene una classe interna che usa. Con questa tecnica le cose sarebbero molto più semplici
Esempio (c #)
[imprint List<Person> as peopleList]
public class People : PersonBase
{
public void SomeMethod()
{
DoSomething(this.Count); //Count is from List
}
}
//Now People can be treated as an List<Person>
People people = new People();
foreach(Person person in people)
{
...
}
PeopleList è un alias / variablename (di tua scelta) utilizzato internamente per creare alias l'istanza, ma può essere saltato se non necessario. Una cosa che è utile è sovrascrivere un metodo impresso, che potrebbe essere ottenuto con la sintassi di override ordinaria
public override void Add(Person person)
{
DoSomething();
personList.Add(person);
}
nota che quanto sopra è equivalente funzionale (e potrebbe essere riscritto dal compilatore) a:
public class People : PersonBase , IList<Person>
{
private List<Person> personList = new List<Person>();
public override void Add(object obj)
{
this.personList.Add(obj)
}
public override int IndexOf(object obj)
{
return personList.IndexOf(obj)
}
//etc etc for each signature in the interface
}
solo se IList cambierà la tua classe si romperà. IList non cambierà, ma un'interfaccia che tu, qualcuno del tuo team o una terza parte ha progettato potrebbe semplicemente cambiare. Inoltre, questo ti consente di risparmiare un sacco di codice per alcune interfacce / classi astratte.
Avvertimenti
Ci sono un paio di trucchi. Per prima cosa dobbiamo aggiungere la sintassi per chiamare i costruttori delle classi imprinted dal costruttore della classe imprinting.
Inoltre, cosa succede se una classe imprime due classi che hanno lo stesso metodo? In tal caso il compilatore lo rileva e impone alla classe di definire un override di quel metodo (in cui è possibile scegliere se si desidera chiamare una classe imprinted o entrambi)
Quindi cosa ne pensi, sarebbe utile, eventuali avvertimenti? Sembra che sarebbe abbastanza semplice implementare qualcosa del genere nel linguaggio C # ma potrei mancare qualcosa:)
Nota a margine - Perché è diverso dall'eredità multipla
Ok, quindi alcune persone hanno chiesto questo. Perché è diverso dall'ereditarietà multipla e perché non dall'ereditarietà multipla. In C # i metodi sono virtuali o meno.
Diciamo che abbiamo ClassB che eredita da ClassA. ClassA ha i metodi MethodA e MethodB. ClassB sovrascrive MethodA ma non MethodB.
Ora dite che MethodB ha una chiamata a MethodA. se MethodA è virtuale chiamerà l'implementazione che ha ClassB, altrimenti utilizzerà la classe base, il MetodoA di ClassA e finirai per chiedersi perché la tua classe non funziona come dovrebbe.
Secondo la terminologia finora potresti già confonderti. Quindi, cosa succede se ClassB eredita sia da ClassA che da un altro ClassC. Scommetto che sia i programmatori che i compilatori si staranno grattando la testa.
Il vantaggio di questo approccio IMO è che le classi di imprinting sono totalmente incapsulate e non devono essere progettate pensando in particolare all'eredità multipla. Puoi praticamente imprimere qualsiasi cosa.