En C # /. Net, j'ai une classe que je souhaite fournir des points d'extension. Je peux faire cela soit en utilisant l'héritage:
public class Animal {
public virtual void Speak() { }
}
public class Dog : Animal {
public overrides void Speak() => Console.WriteLine("Woof");
}
var dog = new Dog();
dog.Speak();
Ou en utilisant des délégués passés:
public class Animal {
private Action speak;
public Animal(Action speak) => this.speak = speak;
public void Speak() => speak();
}
var dog = new Animal(() => Console.WriteLine("Woof"));
dog.Speak();
Je peux déjà voir des différences entre eux:
Speak
, soit le comportement de la classe de base, soit le comportement de classe dérivé. Lorsque vous utilisez des délégués, le champ délégué pourrait potentiellement contenir null
(bien que avec des types de référence nullables, cela ne devrait pas arriver).Quand est-il approprié d'exposer des points d'extension via héritage et quand est-il approprié d'utiliser des délégués?
Méfiez-vous: ce qui suit ne vous donne que une "règle de pointe" approximative, ce qui n'est sûrement pas un tutoriel complet sur la manière d'utiliser correctement l'héritage, mais vous pouvez l'utiliser comme premier "test Litmus" Pour ce que vous demandiez.
Pour créer des points d'extension comportementale, une approche classique populaire est le modèle de stratégie . Lorsque vous regardez le motif en totalité, vous y trouverez:
Un comportement abstrait (la stratégie) qui est injecté comme un délégué dans une classe de contexte. Dans votre exemple "animal", cela pourrait être une interface ou une classe de base abstraite ISpeakStrategy
, avec des dérivations comme DogSpeakStrategy
ou CatSpeakStrategy
, où un objet ISpeakStrategy
est injecté dans un objet de contexte Animal
.
Héritage pour permettre l'extension de l'ensemble des stratégies disponibles, sans toucher aucun code existant.
Maintenant, il y a des situations où vous pourriez avoir besoin de points d'extension, mais en utilisant le modèle de stratégie de cette manière rend les choses plus complexes que nécessaire:
lorsque l'interface de stratégie ne nécessite qu'une seule méthode et que le nom de l'interface n'est pas vraiment important, il suffit d'utiliser un seul délégué au lieu d'une hiérarchie héritarière à part entière souffrant de
lorsqu'une séparation entre un objet "contexte" et une stratégie n'est pas requise, car la classe de contexte serait triviale/presque vide, il suffit d'utiliser une hiérarchie de héritage autonome suffit.
Pensez donc à la façon dont le point d'extension ressemblerait à la structure de stratégie, alors envisagez de laisser tout ce qui surcharge votre conception.