Modèle de prototype en Java

1. Introduction

Dans ce didacticiel, nous allons en apprendre davantage sur l'un des modèles de conception créative - le modèle de prototype. Dans un premier temps, nous allons expliquer ce modèle, puis procéder à son implémentation en Java.

Nous discuterons également de certains de ses avantages et inconvénients.

2. Modèle de prototype

Le modèle Prototype est généralement utilisé lorsque nous avons une instance de la classe (prototype) et que nous aimerions créer de nouveaux objets en copiant simplement le prototype .

Utilisons une analogie pour mieux comprendre ce modèle.

Dans certains jeux, nous voulons des arbres ou des bâtiments en arrière-plan. Nous pouvons réaliser que nous n'avons pas à créer de nouveaux arbres ou bâtiments et à les rendre à l'écran chaque fois que le personnage bouge.

Donc, nous créons d'abord une instance de l'arbre. Ensuite, nous pouvons créer autant d'arbres que nous le souhaitons à partir de cette instance (prototype) et mettre à jour leurs positions. Nous pouvons également choisir de changer la couleur des arbres pour un nouveau niveau dans le jeu.

Le modèle Prototype est assez similaire. Au lieu de créer de nouveaux objets, nous devons simplement cloner l'instance prototypique.

3. Diagramme UML

Dans le diagramme, nous voyons que le client dit au prototype de se cloner et de créer un objet. Prototype est une interface et déclare une méthode pour se cloner. ConcretePrototype1 et ConcretePrototype2 implémentent l'opération pour se cloner.

4. Mise en œuvre

L'une des façons dont nous pouvons implémenter ce modèle en Java consiste à utiliser la méthode clone () . Pour ce faire, nous implémenterons l' interface clonable .

Lorsque nous essayons de cloner, nous devons décider entre faire une copie superficielle ou une copie profonde . Finalement, cela se résume aux exigences.

Par exemple, si la classe ne contient que des champs primitifs et immuables, nous pouvons utiliser une copie superficielle.

S'il contient des références à des champs mutables, nous devrions opter pour une copie complète. Nous pourrions le faire avec des constructeurs de copie ou la sérialisation et la désérialisation.

Prenons l'exemple que nous avons mentionné précédemment et voyons comment appliquer le modèle Prototype sans utiliser l' interface clonable . Pour ce faire, créons une classe abstraite appelée Tree avec une méthode abstraite 'copy' .

public abstract class Tree { // ... public abstract Tree copy(); }

Maintenant , nous allons dire que nous avons deux implémentations différentes d' arbres appelé Plastic Tree et PineTree :

public class PlasticTree extends Tree { // ... @Override public Tree copy() { PlasticTree plasticTreeClone = new PlasticTree(this.getMass(), this.getHeight()); plasticTreeClone.setPosition(this.getPosition()); return plasticTreeClone; } }
public class PineTree extends Tree { // ... @Override public Tree copy() { PineTree pineTreeClone = new PineTree(this.getMass(), this.getHeight()); pineTreeClone.setPosition(this.getPosition()); return pineTreeClone; } }

Nous voyons donc ici que les classes qui étendent Tree et implémentent la méthode de copie peuvent agir comme des prototypes pour créer une copie d'elles-mêmes.

Le modèle de prototype nous permet également de créer des copies d'objets sans dépendre des classes concrètes . Disons que nous avons une liste d'arbres et que nous aimerions en créer des copies. En raison du polymorphisme, nous pouvons facilement créer plusieurs copies sans connaître les types d'arbres.

5. Test

Maintenant, testons-le:

public class TreePrototypesUnitTest { @Test public void givenAPlasticTreePrototypeWhenClonedThenCreateA_Clone() { // ... PlasticTree plasticTree = new PlasticTree(mass, height); plasticTree.setPosition(position); PlasticTree anotherPlasticTree = (PlasticTree) plasticTree.copy(); anotherPlasticTree.setPosition(otherPosition); assertEquals(position, plasticTree.getPosition()); assertEquals(otherPosition, anotherPlasticTree.getPosition()); } }

Nous voyons que l'arbre a été cloné à partir du prototype et nous avons deux instances différentes de PlasticTree . Nous venons de mettre à jour la position dans le clone et de conserver les autres valeurs.

Clonons maintenant une liste d'arbres:

@Test public void givenA_ListOfTreesWhenClonedThenCreateListOfClones() { // create instances of PlasticTree and PineTree List trees = Arrays.asList(plasticTree, pineTree); List treeClones = trees.stream().map(Tree::copy).collect(toList()); // ... assertEquals(height, plasticTreeClone.getHeight()); assertEquals(position, plasticTreeClone.getPosition()); }

Notez que nous sommes en mesure de faire une copie complète de la liste ici sans dépendre des implémentations concrètes de Tree.

6. Avantages et inconvénients

Ce modèle est pratique lorsque notre nouvel objet n'est que légèrement différent de notre objet existant. Dans certains cas, les instances peuvent n'avoir que quelques combinaisons d'états dans une classe. Ainsi, au lieu de créer de nouvelles instances, nous pouvons créer au préalable les instances avec l'état approprié, puis les cloner quand nous le voulons .

Parfois, nous pouvons rencontrer des sous-classes qui ne diffèrent que par leur état. Nous pouvons éliminer ces sous-classes en créant des prototypes avec l'état initial puis en les clonant.

Le modèle de prototype, comme tous les autres modèles de conception, ne doit être utilisé que lorsque cela est approprié. Puisque nous clonons les objets, le processus peut devenir complexe lorsqu'il y a de nombreuses classes, ce qui entraîne un désordre. De plus, il est difficile de cloner des classes qui ont des références circulaires.

7. Conclusion

Dans ce didacticiel, nous avons appris les concepts clés du modèle Prototype et vu comment l'implémenter en Java. Nous avons également discuté de certains de ses avantages et inconvénients.

Comme d'habitude, le code source de cet article est disponible à l'adresse over sur Github.