Ontwerppatronen het patroon met de fabrieksmethode

In het vorige artikel hebben we het Simple Factory Pattern doorgenomen. In dit artikel zullen we nu het patroon van het Factory Method Design bekijken. In het geval van Simple Factory biedt het een interface om objecten te maken, terwijl de Factory-methode hetzelfde doet, maar daarnaast laat het een subklasse toe om een ​​beslissing te nemen over welke klasse om te instantiëren.

Om het Simple Factory Method-patroon uit te leggen, heb ik het voorbeeld gebruikt van het maken van een object van een auto met verschillende autotypes, zoals Sedan, SUV, enz. Ik zal hetzelfde voorbeeld voortzetten om het patroon van de fabrieksmethode uit te leggen, zodat we een beter beeld hebben idee en continuïteit.

Het probleem

In een eenvoudige fabriek maakten we een object van de autoklasse, maar in feite was het een object van de autoklasse aan het maken op basis van het autotype dat we hebben gepasseerd. Dit was een goede stap om te beginnen met het maken van objecten voor een auto met verschillende typen.

Eerder was ons bedrijf beperkt tot de verkoop van een auto in de VS en heeft het slechts één productiecentrum in de VS. Maar naarmate de tijd vordert, breidt het bedrijf uit en besluit het om auto's in het VK te verkopen en een nieuw productiecentrum in het VK te bouwen.

In beide productiecentra werkt onze oude code voor het bouwen van auto's prima, maar om de klanttevredenheid te verbeteren, beslist het bedrijf over enkele wijzigingen in het automodel, maar alleen voor Britse auto's. In dit stadium mislukt onze code voor het bouwen van een object van een auto, omdat we slechts enkele extra functies (kenmerken) nodig hebben voor slechts één specifiek type auto's.

We hebben in dit geval twee opties: ofwel de huidige code wijzigen (meerdere if else-voorwaarden) om het gewenste object van de auto te krijgen, of onze klassen zodanig herstructureren dat deze niet vies zijn, anders de omstandigheden in uw klas en in de toekomst als u wilt een paar extra functies toevoegen, maar alleen voor beperkte typen klassen.

De eerste benadering waar niemand zich graag mee zou willen bemoeien omdat het een soort lappendeken is dat je in je code aan het doen bent en niet de echte implementatie. In de volgende sectie zullen we zien hoe we de tweede benadering kunnen implementeren met behulp van het Factory Method-ontwerppatroon.

De oplossing

Dit ontwerppatroon valt onder de categorie Structuurpatroon, dus het is meer bezig met hoe je je klassen structureert. Laten we dus naar de oplossing van ons probleem gaan door onze klassen op de juiste manier te structureren.

In een eenvoudige fabriek hebben we geen structuur gebruikt omdat we slechts één klasse nodig hadden die verantwoordelijk was voor het maken van een object van de auto. Op basis van het huidige probleem, moeten we een afzonderlijke fabrieksklasse creëren voor beide productiecentra, dus we willen ervoor zorgen dat al onze fabrieken hetzelfde proces volgen om een ​​object van een klasse te maken. Daarom zullen we één interface maken die zowel de Amerikaanse als de Britse fabriek zullen implementeren.

interface carFactory public function buildCar ($ type); 

Nu is onze interface voor fabrieken gereed en wordt het tijd om klassen van onze fabrieken te maken, die de Amerikaanse en Britse autofabriek zijn.

// Fabrieksklasse om Amerikaanse basisklasse USCarFactory te bouwen implementeert carFactory public function __construct ()  public function buildCar ($ type) $ car = null; switch ($ type) case 'suv': $ car = new USSuvFactory (); breken; case 'sedan': $ car = new USSedanFactory (); breken; standaard: $ car = new USSedanFactory (); breken;  retourneer $ auto;  // Fabrieksklasse om Britse basisklasse te bouwen UKCarFactory implementeert carFactory public function __construct ()  public function buildCar ($ type) $ car = null; switch ($ type) case 'suv': $ car = new UKSuvFactory (); breken; case 'sedan': $ car = new UKSedanFactory (); breken; standaard: $ car = new UKSedanFactory (); breken;  retourneer $ auto; 

In deze fase hebben we onze fabrieksklassen klaar, en het is nu tijd om onze concrete klasse te maken. Maar net als bij de fabriek willen we dat onze concrete klassen enkele vereiste methoden implementeren die voor alle concrete klassen hetzelfde zijn.

interface auto openbare functie getLocation (); openbare functie getType (); 

We hebben heel basismethoden aan onze klas toegevoegd om de locatie en het type auto te krijgen. Nu zullen we onze concrete klassen implementeren zoals hieronder.

klasse USSuvFactory implementeert auto privé $ locatie; privé $ carType; publieke functie __construct () $ this-> location = 'US'; $ this-> carType = 'SUV';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType;  class USSedanFactory implementeert auto private $ location; privé $ carType; publieke functie __construct () $ this-> location = 'US'; $ this-> carType = 'Sedan';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType;  class UKSuvFactory implementeert auto private $ location; privé $ carType; publieke functie __construct () $ this-> location = 'UK'; $ this-> carType = 'SUV';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType;  class UKSedanFactory implementeert auto private $ location; privé $ carType; publieke functie __construct () $ this-> location = 'UK'; $ this-> carType = 'Sedan';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType; 

We zijn klaar met de implementatie van onze concrete klassen, die eigenlijk een object van de auto zijn op basis van locatie en type auto. Hier blijft wat over om deze implementatie te gebruiken om te zien hoe het ons hierboven uiteengezette probleem oplost.

// US Car Factory $ USFactory = new USCarFactory (); // Amerikaans SUV-model $ USSuv = $ USFactory-> buildCar ('suv'); echo $ USSuv-> getLocation (). ' gebaseerd '. $ USSuv-> getType (); // Amerikaans sedanmodel $ USSedan = $ USFactory-> buildCar ('sedan'); echo $ USSedan-> getLocation (). ' gebaseerd '. $ USSedan-> getType (); // UK Car Factory $ UKFactory = new UKCarFactory (); // UK-gebaseerd SUV-model $ UKSuv = $ UKFactory-> buildCar ('suv'); echo $ UKSuv-> getLocation (). ' gebaseerd '. $ UKSuv-> getType (); // UK-gebaseerd Sedan-model $ UKSedan = $ UKFactory-> buildCar ('sedan'); echo $ UKSedan-> getLocation (). ' gebaseerd '. $ UKSedan-> getType ();

Je kunt zeggen dat we effectief objecten van alle mogelijke typen auto's hebben gemaakt met de locatie. Onze lessen zijn nu goed gestructureerd, dus er zal niet veel moeite zijn om een ​​nieuwe fabriek toe te voegen.  

Een nieuwe fabrieksklasse toevoegen

Laten we ons voorstellen dat een bedrijf heeft besloten om een ​​nieuw productiecentrum in Australië te beginnen.

Omdat onze klassen nu goed gestructureerd zijn, is er geen probleem meer met het toevoegen van een nieuwe klasse om een ​​auto-object te bouwen voor het Australische productiecentrum. 

// Fabrieksklasse om AUS-gebaseerde centrale klasse AUSCarFactory-implementaties te bouwen carFactory public function __construct ()  public function buildCar ($ type) $ car = null; switch ($ type) case 'suv': $ car = new AUSSuvFactory (); breken; case 'sedan': $ car = new AUSSedanFactory (); breken; standaard: $ car = new AUSSedanFactory (); breken;  retourneer $ auto;  // Betonklassen voor AUS-gebaseerde centrumklasse AUSSuvFactory implementeert auto private $ location; privé $ carType; publieke functie __construct () $ this-> location = 'AUS'; $ this-> carType = 'SUV';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType;  klasse AUSSedanFactory implementeert auto private $ location; privé $ carType; publieke functie __construct () $ this-> location = 'AUS'; $ this-> carType = 'Sedan';  openbare functie getLocation () return $ this-> location;  openbare functie getType () return $ this-> carType;  // AUS Car Factory $ AUSFactory = nieuwe AUSCarFactory (); // AUS gebaseerd SUV-model $ AUSSuv = $ AUSFactory-> buildCar ('suv'); echo $ AUSSuv-> getLocation (). ' gebaseerd '. $ AUSSuv-> getType (); // AUS gebaseerd sedan model $ AUSSedan = $ AUSFactory-> buildCar ('sedan'); echo $ AUSSedan-> getLocation (). ' gebaseerd '. $ AUSSedan-> getType ();

Afsluiten

We hebben dus gezien hoe we onze klassen zodanig kunnen structureren dat ze kunnen worden uitgebreid zonder wijzigingen in je basisklassen en clientcode aan te brengen. Voel je vrij om je invoer toe te voegen in de commentaarsectie hieronder of tweet me op @XpertDevelopers.