Introduksjon til Creational Design Patterns

1. Introduksjon

I programvareteknikk beskriver et designmønster en etablert løsning på de vanligste problemene innen programvaredesign. Det representerer de beste metodene som har utviklet seg over en lang periode gjennom prøving og feiling av erfarne programvareutviklere.

Designmønstre fikk popularitet etter at boka Designmønstre: Elementer av gjenbrukbar objektorientert programvare ble utgitt i 1994 av Erich Gamma, John Vlissides, Ralph Johnson og Richard Helm (også kjent som Gang of Four eller GoF).

I denne artikkelen vil vi utforske mønstre for skapende design og deres typer. Vi vil også se på noen kodeeksempler og diskutere situasjonene når disse mønstrene passer til vårt design.

2. Creational Design Patterns

Creational Design Patterns er opptatt av måten objekter blir opprettet på. De reduserer kompleksiteten og ustabiliteten ved å lage objekter på en kontrollert måte.

De ny operatøren blir ofte ansett som skadelig da den sprer gjenstander over hele applikasjonen. Over tid kan det bli utfordrende å endre en implementering fordi klassene blir tett koblet.

Creational Design Patterns løser dette problemet ved å koble klienten helt fra selve initialiseringsprosessen.

I denne artikkelen vil vi diskutere fire typer skapelsesmønster:

  1. Singleton - Sikrer at det maksimalt bare finnes en forekomst av et objekt gjennom hele applikasjonen
  2. Fabrikkmetode - Oppretter objekter fra flere relaterte klasser uten å spesifisere det eksakte objektet som skal opprettes
  3. Abstract Factory - Oppretter familier med relaterte avhengige objekter
  4. ByggerKonstruerer komplekse objekter ved hjelp av trinnvis tilnærming

La oss nå diskutere hvert av disse mønstrene i detalj.

3. Singleton designmønster

Singleton Design Pattern har som mål å kontrollere initialisering av objekter fra en bestemt klasse innen sikre at bare én forekomst av objektet eksisterer i hele Java Virtual Machine.

En Singleton-klasse gir også ett unikt globalt tilgangspunkt til objektet, slik at hvert påfølgende anrop til tilgangspunktet bare returnerer det bestemte objektet.

3.1. Singleton mønstereksempel

Selv om Singleton-mønsteret ble introdusert av GoF, er den opprinnelige implementeringen kjent for å være problematisk i flertrådede scenarier.

Så her skal vi følge en mer optimal tilnærming som bruker en statisk indre klasse:

offentlig klasse Singleton {privat Singleton () {} privat statisk klasse SingletonHolder {offentlig statisk endelig Singleton-forekomst = ny Singleton (); } offentlig statisk Singleton getInstance () {return SingletonHolder.instance; }}

Her har vi opprettet en statisk indre klasse som holder instansen av Singleton klasse. Det oppretter forekomsten bare når noen ringer getInstance () metode og ikke når den ytre klassen er lastet.

Dette er en mye brukt tilnærming for en Singleton-klasse, da den ikke krever synkronisering, er trådsikker, håndhever lat initialisering og har relativt mindre kokeplate.

Vær også oppmerksom på at konstruktøren har privat tilgangsmodifikator. Dette er et krav for å lage en Singleton siden a offentlig konstruktør ville bety at alle kunne få tilgang til den og begynne å opprette nye forekomster.

Husk at dette ikke er den originale GoF-implementeringen. For den originale versjonen, vennligst besøk denne koblede Baeldung-artikkelen om Singletons i Java.

3.2. Når skal du bruke Singleton Design Pattern

  • For ressurser som er dyre å lage (som databaseforbindelsesobjekter)
  • Det er god praksis å beholde alle loggere som Singletons, noe som øker ytelsen
  • Klasser som gir tilgang til konfigurasjonsinnstillinger for applikasjonen
  • Klasser som inneholder ressurser som er tilgjengelige i delt modus

4. Fabrikkmetode designmønster

Factory Design Pattern eller Factory Method Design Pattern er et av de mest brukte designmønstrene i Java.

I følge GoF er dette mønsteret “Definerer et grensesnitt for å opprette et objekt, men la underklasser bestemme hvilken klasse du vil starte. Factory-metoden lar en klasse utsette instantiering til underklasser ”.

Dette mønsteret delegerer ansvaret for å initialisere en klasse fra klienten til en bestemt fabrikkklasse ved å lage en type virtuell konstruktør.

For å oppnå dette stoler vi på en fabrikk som gir oss objektene, og skjuler de faktiske implementeringsdetaljene. De opprettet objektene er tilgjengelige ved hjelp av et felles grensesnitt.

4.1. Fabrikkmetode Designmønstereksempel

I dette eksemplet oppretter vi en Polygon grensesnitt som vil bli implementert av flere konkrete klasser. EN PolygonFabrik vil bli brukt til å hente gjenstander fra denne familien:

La oss først lage Polygon grensesnitt:

offentlig grensesnitt Polygon {String getType (); }

Deretter lager vi noen få implementeringer som Torget, Triangel, etc. som implementerer dette grensesnittet og returnerer et objekt av Polygon type.

Nå kan vi lage en fabrikk som tar antall sider som et argument og returnerer riktig implementering av dette grensesnittet:

offentlig klasse PolygonFactory {public Polygon getPolygon (int numberOfSides) {if (numberOfSides == 3) {return new Triangle (); } if (numberOfSides == 4) {return new Square (); } hvis (numberOfSides == 5) {returner ny Pentagon (); } hvis (numberOfSides == 7) {returner nytt Heptagon (); } annet hvis (numberOfSides == 8) {returner ny Octagon (); } returner null; }}

Legg merke til hvordan klienten kan stole på at denne fabrikken gir oss en passende Polygon, uten å måtte initialisere objektet direkte.

4.2. Når skal du bruke fabrikkmetode designmønster

  • Når implementeringen av et grensesnitt eller en abstrakt klasse forventes å endres ofte
  • Når den nåværende implementeringen ikke komfortabelt kan imøtekomme nye endringer
  • Når initialiseringsprosessen er relativt enkel, og konstruktøren bare krever en håndfull parametere

5. Abstrakt fabrikkdesignmønster

I forrige avsnitt så vi hvordan Factory Method-designmønsteret kunne brukes til å lage objekter relatert til en enkelt familie.

Derimot brukes det abstrakte fabrikkdesignmønsteret til å skape familier med relaterte eller avhengige gjenstander. Det kalles også noen ganger en fabrikk med fabrikker.

For en detaljert forklaring, sjekk ut vår abstrakte fabrikkopplæring.

6. Builder Design Pattern

Builder Design Pattern er et annet skapelsesmønster designet for å håndtere konstruksjonen av relativt komplekse gjenstander.

Når kompleksiteten ved å skape objekt øker, kan Builder-mønsteret skille ut instantiseringsprosessen ved å bruke et annet objekt (en builder) for å konstruere objektet.

Denne byggmesteren kan deretter brukes til å lage mange andre lignende representasjoner ved hjelp av en enkel trinnvis tilnærming.

6.1. Byggmønstereksempel

Det originale Builder Design Pattern introdusert av GoF fokuserer på abstraksjon og er veldig bra når du arbeider med komplekse objekter, men designet er imidlertid litt komplisert.

Joshua Bloch introduserte i sin bok Effektiv Java en forbedret versjon av byggemønsteret som er rent, lett lesbart (fordi det bruker flytende design) og er lett å bruke fra kundens perspektiv. I dette eksemplet vil vi diskutere den versjonen.

Dette eksemplet har bare en klasse, Bankkonto som inneholder en byggmester som en statisk indre klasse:

offentlig klasse BankAccount {private String name; privat strengkontoNummer; privat streng e-post; privat boolsk nyhetsbrev; // constructors / getters public static class BankAccountBuilder {// builder code}} 

Vær oppmerksom på at alle tilgangsmodifikatorer på feltene er erklært privat siden vi ikke vil at ytre objekter skal få tilgang til dem direkte.

Konstruktøren er også privat slik at bare byggmesteren som er tilordnet denne klassen, får tilgang til den. Alle egenskapene satt i konstruktøren er hentet fra byggeobjektet som vi leverer som et argument.

Vi har definert BankAccountBuilder i en statisk indre klasse:

offentlig statisk klasse BankAccountBuilder {private strengnavn; privat strengkontoNummer; privat streng e-post; privat boolsk nyhetsbrev; public BankAccountBuilder (String name, String accountNumber) {this.name = name; this.accountNumber = accountNumber; } offentlig BankAccountBuilder withEmail (streng e-post) {this.email = email; returner dette; } offentlig BankAccountBuilder wantNewsletter (boolsk nyhetsbrev) {this.newsletter = newsletter; returner dette; } public BankAccount build () {return new BankAccount (this); }} 

Legg merke til at vi har erklært det samme settet med felt som den ytre klassen inneholder. Eventuelle obligatoriske felt kreves som argumenter for den indre klassens konstruktør, mens de gjenværende valgfrie feltene kan spesifiseres ved hjelp av settermetodene.

Denne implementeringen støtter også den flytende designtilnærmingen ved å få settermetodene til å returnere byggerobjektet.

Til slutt kaller byggemetoden den private konstruktøren til den ytre klassen og sender seg selv som argumentet. De returnerte Bankkonto vil bli instansert med parametrene satt av BankAccountBuilder.

La oss se et raskt eksempel på byggemønsteret i aksjon:

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

6.2. Når skal jeg bruke byggmønster

  1. Når prosessen involvert i å lage et objekt er ekstremt kompleks, med mange obligatoriske og valgfrie parametere
  2. Når en økning i antall konstruktorparametre fører til en stor liste over konstruktører
  3. Når klienten forventer forskjellige fremstillinger for objektet som er konstruert

7. Konklusjon

I denne artikkelen lærte vi om skapelsesdesignmønstre i Java. Vi diskuterte også deres fire forskjellige typer, det vil si Singleton, Factory Method, Abstract Factory og Builder Pattern, fordelene, eksemplene og når skal vi bruke dem.

Som alltid er de komplette kodebitene tilgjengelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found