Organiseren van code gaat ons een hoop pijn besparen. Met behulp van de functies van Objectgeoriënteerd programmeren kunnen we bepaalde ontwerppatronen gebruiken om de leesbaarheid te verbeteren, redundantie te verminderen en indien nodig abstracties te creëren. Eén zo’n patroon is het factory pattern.
Het factory pattern is een type Object Oriented pattern dat de DRY methodologie volgt. Zoals de naam al doet vermoeden, worden object instanties gecreëerd door gebruik te maken van een fabriek om het benodigde object voor ons te maken.
Laten we eens kijken naar een zeer eenvoudig voorbeeld van het gebruik van het fabriekspatroon om een alligator
object samen te stellen. Om dat te doen moeten we eerst fabrieken maken die de alligator
onderdelen voor ons maken:
class TailFactory { constructor(props) { this.tailLength = props.tailLength; }};class TorsoFactory { constructor(props) { this.color = props.color; }};class HeadFactory { constructor(props) { this.snoutLenth = props.snoutLenth; }};
Nu maken we een klasse die fungeert als intermediair tussen de eigenlijke fabrieken klassen en de gebruiker. Laten we dit de ReptilePartFactory
noemen:
class ReptilePartFactory { constructor(type, props) { if(type === "tail") return new TailFactory(props); if(type === "torso") return new TorsoFactory(props); if(type === "head") return new HeadFactory(props); }};
Laten we nu de eigenlijke alligator in elkaar zetten en de ReptilePartFactory
gebruiken om de benodigde onderdelen voor ons te krijgen:
let alligator = {};let alligatorProps = { tailLength : 2.5, color: "green", snoutLenth: 1};//gets a tail from the tail factoryalligator.tail = new ReptilePartFactory("tail", alligatorProps); //gets a torso from the torso factoryalligator.torso = new ReptilePartFactory("torso", alligatorProps);//gets a head from the head factoryalligator.head = new ReptilePartFactory("head", alligatorProps);
Neem het patroon hierboven in ogenschouw, het lijkt erop dat we dezelfde ReptilePartFactory
kunnen gebruiken om onderdelen voor alligator-achtige objecten te maken. De fabrieken op de achtergrond zouden nooit iets hoeven te weten over de aard van het uiteindelijke object.
Dus, het gebruik van het fabriekspatroon geeft ons bepaalde voordelen:
- Dynamische objectcreatie: Het kan worden gebruikt in gevallen waarin het type van het object in runtime wordt bepaald.
- Abstractie: De gebruiker hoeft nooit echt toegang te krijgen tot de constructor van het eigenlijke object.
- Herbruikbaarheid/Onderhoud: Dezelfde fabrieken kunnen worden gebruikt voor soortgelijke objecten en het stelt ons in staat om gemakkelijk nieuwe objectklassen toe te voegen / te verwijderen zonder veel code te veranderen.
Nu we enig begrip hebben van het fabriekspatroon, laten we een beetje verkennen op het schrijven van betere fabriekspatrooncode.
Het bovenstaande voorbeeld maakt gebruik van een if-ladder om uit te zoeken welke fabriek moet worden aangeroepen op basis van gebruikersinvoer. Dit is een eenvoudige implementatie, intuïtief en niet erg open voor veranderingen. Als we later nieuwe onderdelen willen toevoegen, dan zouden we de ReptilePartFactory
moeten verstoren. Dit is een schending van de SOLID principes, die stelt “Software entiteiten (klassen, modules, functies, enz.) moeten open zijn voor uitbreiding, maar gesloten voor wijziging”.
Hoe zit het met het opslaan van de factory classes in een object en het aanroepen van de benodigde part factory door het part dat we willen als key te gebruiken? Eerst zouden we de fabrieken moeten registreren, het zou zo eenvoudig zijn als:
let registeredPartFactories = {};registeredPartFactories = class TailFactory{ ...};registeredPartFactories = class TorsoFactory { ...};registeredPartFactories = class HeadFactory { ...};
En nu kan de abstracte laag de fabrieken op deze manier aanroepen:
class ReptilePartFactory { constructor(type, props) { return new registeredPartFactories(props); }};
Deze aanpak is veel schoner en maakt het mogelijk om onze fabrieken uit te breiden zonder de code in de ReptilePartFactory
te beïnvloeden.
Tot slot
Er zijn verschillende andere object georiënteerde patronen die ook de leesbaarheid en kwaliteit verhogen. Dus voordat je het factory pattern gebruikt, controleer of er een echte behoefte aan is. Als je herhaaldelijk gelijksoortige objecten gaat maken en ook een laag nodig hebt om nieuwe instanties te maken met deze objecten, terwijl je een zekere mate van abstractie biedt aan de creatie logica, dan ja – is het factory pattern een goede optie.