J'ai une interface qui a une certaine quantité de fonctionnalités bien définies. Disons:
interface BakeryInterface {
public function createCookies();
public function createIceCream();
}
Cela fonctionne bien pour la plupart des implémentations de l'interface, mais dans quelques cas, j'ai besoin d'ajouter de nouvelles fonctionnalités (comme peut-être intégrées dans une nouvelle méthode createBrownies()
). L'approche évidente / naïve pour ce faire serait d'étendre l'interface:
interface BrownieBakeryInterface extends BakeryInterface {
public function createBrownies();
}
Mais a un assez gros inconvénient en ce que je ne peux pas ajouter la nouvelle fonctionnalité sans modifier l'API existante (comme changer la classe pour utiliser la nouvelle interface).
Je pensais utiliser un adaptateur pour ajouter la fonctionnalité après l'instanciation:
class BrownieAdapter {
private brownieBakery;
public function construct(BakeryInterface bakery) {
this->brownieBakery = bakery;
}
public function createBrownies() {
/* ... */
}
}
Ce qui me rapporterait quelque chose comme:
bakery = new Bakery();
bakery = new BrownieBakery(bakery);
bakery->createBrownies();
Cela semble être une bonne solution au problème, mais je me demande si j'éveille les anciens dieux en le faisant. L'adaptateur est-il la voie à suivre? Y a-t-il un meilleur schéma à suivre? Ou dois-je vraiment mordre la balle et étendre simplement l'interface d'origine?
Réponses:
Tous les modèles de corps de poignée peuvent correspondre à la description, en fonction de vos exigences exactes, de votre langue et du niveau d'abstraction requis.
L'approche puriste serait le modèle Décorateur , qui fait exactement ce que vous recherchez, ajoute dynamiquement des responsabilités aux objets. Si vous construisez des boulangeries, c'est définitivement exagéré et vous devriez simplement aller avec l'adaptateur.
la source
Enquêter sur le concept de réutilisation horizontale , où vous pouvez trouver des trucs comme Traits , la programmation orientée aspect encore expérimentale mais déjà à l'épreuve de la production et les Mixins parfois détestés .
Un moyen direct d'ajouter des méthodes à une classe dépend également du langage de programmation. Ruby permet le patch de singe tandis que l' héritage basé sur un prototype de Javascript , où les classes n'existent pas vraiment, vous créez un objet et vous le copiez simplement et continuez à y ajouter, par exemple:
Enfin, vous pouvez également émuler la réutilisation horizontale, ou la «modification» et l '«ajout» à l'exécution du comportement de classe / objet avec réflexion .
la source
S'il existe une exigence selon laquelle l'
bakery
instance doit changer son comportement de manière dynamique (en fonction des actions de l'utilisateur, etc.), vous devez opter pour le modèle Décorateur .Si
bakery
ne change pas son comportement de manière dynamique mais que vous ne pouvez pas modifierBakery class
(API externe, etc.), vous devez opter pour le modèle d'adaptateur .Si
bakery
ne change pas son comportement dynamiquement et que vous pouvez le modifier,Bakery class
vous devez étendre l'interface existante (comme vous l'avez initialement proposé) ou introduire une nouvelle interfaceBrownieInterface
et laisserBakery
implémenter deux interfacesBakeryInterface
etBrownieInterface
.Sinon, vous allez ajouter une complexité inutile à votre code (en utilisant le modèle Decorator) sans raison valable!
la source
Vous avez rencontré le problème d'expression. Cet article de Stuart Sierra traite de la solution des clojures, mais il donne également un exemple en Java et répertorie les solutions populaires en OO classique.
Il y a aussi cette présentation de Chris Houser qui traite à peu près du même terrain.
la source