Contesto: Nello spirito di "program to an interface, not an implementation" e Haskell type classes e come esperimento di codifica, sto pensando a cosa significherebbe creare un'API basata principalmente sulla combinazione di interfacce e metodi di estensione. Ho due linee guida in mente:"programmazione di un'interfaccia" utilizzando metodi di estensione: quando va a finire troppo lontano?
Evitare l'ereditarietà della classe quando possibile. Interfacce dovrebbero essere implementati come
sealed class
es.
(Questo per due ragioni:. Primo, perché sottoclassi solleva alcune questioni sgradevoli su come specificare e far rispettare il contratto di classe di base nelle sue classi derivate In secondo luogo, e questo è il tipo di Haskell classe di influenza, il polimorfismo non richiede la creazione di sottoclassi .)Evitare metodi di istanza, ove possibile. Se può essere fatto con i metodi di estensione, questi sono preferiti.
(Questo è inteso per aiutare a mantenere le interfacce compatta:.. Tutto ciò che può essere fatto mediante una combinazione di altri metodi di istanza diventa un metodo di estensione Resta nell'interfaccia è funzionalità di base, e metodi che cambia stato in particolare)
Problema: Ho problemi con la seconda linea guida. Considerate questo:
interface IApple { }
static void Eat(this IApple apple)
{
Console.WriteLine("Yummy, that was good!");
}
interface IRottenApple : IApple { }
static void Eat(this IRottenApple apple)
{
Console.WriteLine("Eat it yourself, you disgusting human, you!");
}
sealed class RottenApple : IRottenApple { }
IApple apple = new RottenApple();
// API user might expect virtual dispatch to happen (as usual) when 'Eat' is called:
apple.Eat(); // ==> "Yummy, that was good!"
Ovviamente, per il risultato atteso ("Eat it yourself…"
), Eat
dovrebbe essere un metodo di istanza regolare.
Domanda: Quale sarebbe una linea guida raffinata/più accurata sull'uso dei metodi di estensione rispetto ai metodi di istanza (virtuali)? Quando l'uso dei metodi di estensione per "programmare su un'interfaccia" è eccessivo? In quali casi sono effettivamente necessari i metodi di istanza?
Non so se lo è una regola generale chiara, quindi non mi aspetto una risposta universale perfetta. Sono apprezzati eventuali miglioramenti ben argomentati alla linea guida (2) sopra riportata.
penso un posto migliore per iniziare sarebbe '' IEnumerable Rathe r di un esempio inventato. –
ChaosPandion
beh, hai * kindof * violato la regola # 1 facendo 'IRottenApple' estendere' IApple' ... (anche se qui si legge * ereditarietà * classe) –
@John: Non credo. Credo che l'ereditarietà * dell'interfaccia * eviti molti dei problemi della sottoclasse. (Ad esempio: un metodo sottoposto a override deve essere chiamato dalla classe derivata o no? Questa domanda svanisce semplicemente quando non si accetta la sottoclasse.) – stakx