Prototype patroon in Java

1. Inleiding

In deze tutorial gaan we leren over een van de Creational Design Patterns - het Prototype-patroon. Eerst leggen we dit patroon uit en gaan we het vervolgens in Java implementeren.

We zullen ook enkele van de voor- en nadelen bespreken.

2. Prototype patroon

Het prototype-patroon is over het algemeen gebruikt als we een instantie van de klasse (prototype) hebben en we willen nieuwe objecten maken door gewoon het prototype te kopiëren.

Laten we een analogie gebruiken om dit patroon beter te begrijpen.

In sommige games willen we bomen of gebouwen op de achtergrond. We realiseren ons misschien dat we niet elke keer dat het personage beweegt nieuwe bomen of gebouwen hoeven te maken en deze op het scherm weer te geven.

We maken dus eerst een instantie van de boom. Vervolgens kunnen we vanuit deze instantie (prototype) zoveel bomen maken als we willen en hun posities bijwerken. We kunnen er ook voor kiezen om de kleur van de bomen te veranderen voor een nieuw niveau in het spel.

Het prototypepatroon lijkt veel op elkaar. In plaats van nieuwe objecten te maken, we hoeven alleen de prototypische instantie te klonen.

3. UML-diagram

In het diagram zien we dat de klant het prototype vertelt om zichzelf te klonen en een object te maken. Voorlopig ontwerp is een interface en verklaart een methode om zichzelf te klonen. Betonprototype 1 en Betonprototype 2 de operatie implementeren om zichzelf te klonen.

4. Implementatie

Een van de manieren waarop we dit patroon in Java kunnen implementeren, is door de kloon () methode. Om dit te doen, zouden we het Te klonen koppel.

Als we proberen te klonen, we moeten kiezen tussen het maken van een ondiepe of een diepe kopie. Uiteindelijk komt het neer op de eisen.

Als de klasse bijvoorbeeld alleen primitieve en onveranderlijke velden bevat, kunnen we een ondiepe kopie gebruiken.

Als het verwijzingen naar veranderlijke velden bevat, moeten we voor een diepe kopie gaan. We zouden dat kunnen doen met kopieer constructeurs of serialisatie en deserialisatie.

Laten we het voorbeeld nemen dat we eerder noemden en verder gaan om te zien hoe u het Prototype-patroon kunt toepassen zonder de Te klonen koppel. Om dit te doen, maken we een abstract klasse gebeld Boom Met een abstract methode 'kopiëren'.

openbare abstracte klasse Tree {// ... openbare abstracte Tree copy (); }

Laten we nu zeggen dat we twee verschillende implementaties hebben van Boom gebeld PlasticTree en Dennenboom:

public class PlasticTree breidt Tree uit {// ... @Override public Tree copy () {PlasticTree plasticTreeClone = nieuwe PlasticTree (this.getMass (), this.getHeight ()); plasticTreeClone.setPosition (this.getPosition ()); terug plasticTreeClone; }}
openbare klasse PineTree breidt Tree uit {// ... @Override openbare Tree copy () {PineTree pineTreeClone = nieuwe PineTree (this.getMass (), this.getHeight ()); pineTreeClone.setPosition (this.getPosition ()); retourneer pineTreeClone; }}

Dus hier zien we dat de klassen zich uitstrekken Boom en implementeer het kopiëren methode kan dienen als prototypes voor het maken van een kopie van zichzelf.

Met prototypepatroon kunnen we ook kopieën van objecten maken zonder afhankelijk te zijn van de concrete klassen. Laten we zeggen dat we een lijst met bomen hebben en we zouden er graag kopieën van willen maken. Vanwege polymorfisme kunnen we gemakkelijk meerdere kopieën maken zonder de soorten bomen te kennen.

5. Testen

Laten we het nu testen:

openbare klasse TreePrototypesUnitTest {@Test openbare leegte gegevenAPlasticTreePrototypeWhenClonedThenCreateA_Clone () {// ... PlasticTree plasticTree = nieuwe PlasticTree (massa, hoogte); plasticTree.setPosition (positie); PlasticTree anotherPlasticTree = (PlasticTree) plasticTree.copy (); anotherPlasticTree.setPosition (otherPosition); assertEquals (positie, plasticTree.getPosition ()); assertEquals (otherPosition, anotherPlasticTree.getPosition ()); }}

We zien dat de boom is gekloond vanuit het prototype en we hebben twee verschillende exemplaren van PlasticTree. We hebben zojuist de positie in de kloon bijgewerkt en de andere waarden behouden.

Laten we nu een lijst met bomen klonen:

@Test openbare leegte gegevenA_ListOfTreesWhenClonedThenCreateListOfClones () {// maak instanties van PlasticTree en PineTree List bomen = Arrays.asList (plasticTree, pineTree); Lijst treeClones = trees.stream (). Map (Tree :: copy) .collect (toList ()); // ... assertEquals (hoogte, plasticTreeClone.getHeight ()); assertEquals (positie, plasticTreeClone.getPosition ()); }

Merk op dat we hier een diepe kopie van de lijst kunnen maken zonder afhankelijk te zijn van de concrete implementaties van Boom.

6. Voordelen en nadelen

Dit patroon is handig als ons nieuwe object maar een klein beetje verschilt van ons bestaande. In sommige gevallen hebben instanties mogelijk maar een paar combinaties van status in een klasse. Dus in plaats van nieuwe instanties te maken, we kunnen de instanties van tevoren met de juiste status maken en ze vervolgens klonen wanneer we maar willen.

Soms kunnen we subklassen tegenkomen die alleen verschillen in hun staat. We kunnen die subklassen elimineren door prototypes met de oorspronkelijke staat te maken en ze vervolgens te klonen.

Prototypepatroon mag, net als elk ander ontwerppatroon, alleen worden gebruikt als het passend is. Omdat we de objecten klonen, kan het proces complex worden als er veel klassen zijn, wat resulteert in een puinhoop. Bovendien is het moeilijk om klassen te klonen die kringverwijzingen hebben.

7. Conclusie

In deze tutorial hebben we de belangrijkste concepten van het prototypepatroon geleerd en gezien hoe we het in Java konden implementeren. We hebben ook enkele van de voor- en nadelen besproken.

Zoals gewoonlijk is de broncode voor dit artikel beschikbaar op Github.