Inleiding tot Creational Design Patterns

1. Inleiding

In software engineering beschrijft een ontwerppatroon een gevestigde oplossing voor de meest voorkomende problemen bij het ontwerpen van software. Het vertegenwoordigt de best practices die gedurende een lange periode zijn ontwikkeld door middel van vallen en opstaan ​​door ervaren softwareontwikkelaars.

Design Patterns werd populair nadat het boek Design Patterns: Elements of Reusable Object-Oriented Software in 1994 werd gepubliceerd door Erich Gamma, John Vlissides, Ralph Johnson en Richard Helm (ook bekend als Gang of Four of GoF).

In dit artikel zullen we creatieve ontwerppatronen en hun typen onderzoeken. We zullen ook enkele codevoorbeelden bekijken en de situaties bespreken waarin deze patronen in ons ontwerp passen.

2. Creationele ontwerppatronen

Creational Design Patterns houdt zich bezig met de manier waarop objecten worden gemaakt. Ze verminderen de complexiteit en instabiliteit door op een gecontroleerde manier objecten te creëren.

De nieuw operator wordt vaak als schadelijk beschouwd omdat het objecten door de hele applicatie verstrooit. Na verloop van tijd kan het een uitdaging worden om een ​​implementatie te wijzigen omdat klassen nauw met elkaar worden gekoppeld.

Creational Design Patterns lost dit probleem op door de client volledig los te koppelen van het daadwerkelijke initialisatieproces.

In dit artikel bespreken we vier soorten Creational Design Pattern:

  1. Singleton - Zorgt ervoor dat er in de hele applicatie maximaal één instantie van een object bestaat
  2. Fabrieksmethode - Maakt objecten van verschillende gerelateerde klassen zonder het exacte object op te geven dat moet worden gemaakt
  3. Abstract Factory - Maakt families van gerelateerde afhankelijke objecten
  4. BouwerConstrueert complexe objecten met een stapsgewijze aanpak

Laten we nu elk van deze patronen in detail bespreken.

3. Singleton-ontwerppatroon

Het Singleton Design Pattern is bedoeld om de initialisatie van objecten van een bepaalde klasse te controleren door ervoor zorgen dat er slechts één exemplaar van het object aanwezig is in de Java Virtual Machine.

Een Singleton-klasse biedt ook één uniek globaal toegangspunt tot het object, zodat elke volgende aanroep naar het toegangspunt alleen dat specifieke object retourneert.

3.1. Singleton Pattern Voorbeeld

Hoewel het Singleton-patroon werd geïntroduceerd door GoF, is het bekend dat de oorspronkelijke implementatie problematisch is in scenario's met meerdere threads.

Dus hier gaan we een meer optimale benadering volgen die gebruik maakt van een statische innerlijke klasse:

openbare klasse Singleton {privé Singleton () {} privé statische klasse SingletonHolder {openbare statische laatste Singleton-instantie = nieuwe Singleton (); } openbare statische Singleton getInstance () {retourneer SingletonHolder.instance; }}

Hier hebben we een statisch inner class die de instantie van de Singleton klasse. Het maakt de instantie alleen wanneer iemand het getInstance () methode en niet wanneer de buitenste klasse is geladen.

Dit is een veel gebruikte benadering voor een Singleton-klasse omdat het geen synchronisatie vereist, thread-safe is, luie initialisatie afdwingt en relatief minder standaard is.

Merk ook op dat de constructor de privaat toegangsmodificator. Dit is een vereiste voor het maken van een Singleton aangezien een openbaar constructor zou betekenen dat iedereen er toegang toe heeft en nieuwe instanties kan maken.

Onthoud dat dit niet de originele GoF-implementatie is. Ga voor de originele versie naar dit gelinkte Baeldung-artikel over Singletons in Java.

3.2. Wanneer Singleton Design Pattern gebruiken

  • Voor resources die duur zijn om te maken (zoals databaseverbindingsobjecten)
  • Het is een goede gewoonte om alle loggers als Singletons te houden, wat de prestaties verhoogt
  • Klassen die toegang bieden tot configuratie-instellingen voor de applicatie
  • Klassen die bronnen bevatten die toegankelijk zijn in de gedeelde modus

4. Fabrieksmethode ontwerppatroon

Het Factory Design Pattern of Factory Method Design Pattern is een van de meest gebruikte ontwerppatronen in Java.

Volgens GoF is dit patroon “Definieert een interface voor het maken van een object, maar laat subklassen beslissen welke klasse wordt geïnstantieerd. Met de Factory-methode kan een klasse instantiatie uitstellen naar subklassen ”.

Dit patroon delegeert de verantwoordelijkheid voor het initialiseren van een klasse van de client naar een bepaalde fabrieksklasse door een type virtuele constructor te maken.

Om dit te bereiken, vertrouwen we op een fabriek die ons de objecten levert en de feitelijke uitvoeringsdetails verbergt. De gemaakte objecten zijn toegankelijk via een gemeenschappelijke interface.

4.1. Fabrieksmethode Ontwerppatroon Voorbeeld

In dit voorbeeld maken we een Veelhoek interface die zal worden geïmplementeerd door verschillende concrete klassen. EEN PolygonFactory wordt gebruikt om objecten uit deze familie op te halen:

Laten we eerst het Veelhoek koppel:

openbare interface Polygoon {String getType (); }

Vervolgens maken we een aantal implementaties, zoals Plein, Driehoek, etc. die deze interface implementeren en een object retourneren van Veelhoek type.

Nu kunnen we een fabriek maken die het aantal zijden als argument neemt en de juiste implementatie van deze interface retourneert:

openbare klasse PolygonFactory {openbare Polygoon getPolygon (int numberOfSides) {if (numberOfSides == 3) {return new Triangle (); } if (numberOfSides == 4) {return new Square (); } if (numberOfSides == 5) {return new Pentagon (); } if (numberOfSides == 7) {retourneer nieuwe Heptagon (); } else if (numberOfSides == 8) {return new Octagon (); } retourneer null; }}

Merk op hoe de klant op deze fabriek kan vertrouwen om ons een passend te geven Veelhoek, zonder het object direct te hoeven initialiseren.

4.2. Wanneer het ontwerppatroon van de fabrieksmethode moet worden gebruikt

  • Wanneer wordt verwacht dat de implementatie van een interface of een abstracte klasse regelmatig zal veranderen
  • Wanneer de huidige implementatie niet comfortabel nieuwe veranderingen kan accommoderen
  • Wanneer het initialisatieproces relatief eenvoudig is en de constructor slechts een handvol parameters nodig heeft

5. Abstract fabrieksontwerppatroon

In de vorige sectie hebben we gezien hoe het ontwerppatroon Factory Method kan worden gebruikt om objecten te maken die betrekking hebben op een enkele familie.

Daarentegen wordt het Abstract Factory Design Pattern gebruikt om families van verwante of afhankelijke objecten te creëren. Het wordt ook wel een fabriek van fabrieken genoemd.

Voor een uitgebreide uitleg, bekijk onze Abstract Factory tutorial.

6. Bouwer ontwerppatroon

Het Builder-ontwerppatroon is een ander creatief patroon dat is ontworpen om de constructie van relatief complexe objecten aan te pakken.

Wanneer de complexiteit van het maken van een object toeneemt, kan het Builder-patroon het instantiatieproces scheiden door een ander object (een builder) te gebruiken om het object te construeren.

Deze builder kan vervolgens worden gebruikt om vele andere soortgelijke representaties te maken met behulp van een eenvoudige stapsgewijze aanpak.

6.1. Voorbeeld van een Builder-patroon

Het originele Builder-ontwerppatroon dat door GoF is geïntroduceerd, richt zich op abstractie en is erg goed bij het omgaan met complexe objecten, maar het ontwerp is een beetje gecompliceerd.

Joshua Bloch introduceerde in zijn boek Effective Java een verbeterde versie van het builder-patroon dat schoon, goed leesbaar (omdat het gebruik maakt van vloeiend ontwerp) en gemakkelijk te gebruiken is vanuit het perspectief van de klant. In dit voorbeeld bespreken we die versie.

Dit voorbeeld heeft maar één klasse, Bankrekening die een bouwer bevat als een statisch innerlijke klasse:

openbare klasse BankAccount {private String-naam; privé String accountNumber; privé String-e-mail; privé booleaanse nieuwsbrief; // constructors / getters openbare statische klasse BankAccountBuilder {// buildercode}} 

Merk op dat alle toegangsmodificatoren op de velden zijn gedeclareerd privaat omdat we niet willen dat uiterlijke objecten er rechtstreeks toegang toe hebben.

De constructeur is ook privaat zodat alleen de Builder die aan deze klasse is toegewezen, er toegang toe heeft. Alle eigenschappen die in de constructor zijn ingesteld, worden geëxtraheerd uit het builder-object dat we als argument opgeven.

We hebben gedefinieerd BankAccountBuilder in een statisch innerlijke klasse:

openbare statische klasse BankAccountBuilder {private String-naam; privé String accountNumber; privé String-e-mail; privé booleaanse nieuwsbrief; openbare BankAccountBuilder (String naam, String accountNumber) {this.name = naam; this.accountNumber = accountNumber; } openbare BankAccountBuilder withEmail (String e-mail) {this.email = e-mail; dit teruggeven; } openbare BankAccountBuilder wantNewsletter (booleaanse nieuwsbrief) {this.newsletter = nieuwsbrief; dit teruggeven; } public BankAccount build () {retourneer nieuwe BankAccount (dit); }} 

Merk op dat we dezelfde set velden hebben gedeclareerd die de buitenste klasse bevat. Alle verplichte velden zijn vereist als argumenten voor de constructor van de binnenste klasse, terwijl de resterende optionele velden kunnen worden gespecificeerd met behulp van de setter-methoden.

Deze implementatie ondersteunt ook de vloeiende ontwerpbenadering door de setter-methoden het builder-object te laten retourneren.

Ten slotte roept de build-methode de private constructor van de buitenste klasse aan en geeft zichzelf door als argument. De teruggekeerden Bankrekening wordt geïnstantieerd met de parameters die zijn ingesteld door de BankAccountBuilder.

Laten we een snel voorbeeld bekijken van het bouwerpatroon in actie:

BankAccount newAccount = nieuwe BankAccount .BankAccountBuilder ("Jon", "22738022275") .withEmail ("[email protected]") .wantNewsletter (true) .build ();

6.2. Wanneer Builder Pattern gebruiken

  1. Wanneer het proces dat betrokken is bij het maken van een object buitengewoon complex is, met veel verplichte en optionele parameters
  2. Wanneer een toename van het aantal constructorparameters leidt tot een grote lijst met constructors
  3. Wanneer de klant verschillende representaties verwacht voor het object dat is geconstrueerd

7. Conclusie

In dit artikel hebben we geleerd over creatieve ontwerppatronen in Java. We hebben ook hun vier verschillende typen besproken, namelijk Singleton, Factory Method, Abstract Factory en Builder Pattern, hun voordelen, voorbeelden en wanneer moeten we ze gebruiken.

Zoals altijd zijn de volledige codefragmenten beschikbaar op GitHub.