"Hallo Amigo!"
"Hallo Bilaabo!"
"Ons onderwerp van vandaag zal niet alleen interessant zijn - het zal ronduit episch zijn."
"Vandaag ga ik je vertellen wat ontwerppatronen zijn. "
"Cool! Ik heb er veel over gehoord. Ik kan niet wachten!"
"Ervaren programmeurs moeten veel klassen schrijven. Maar het moeilijkste deel van deze taak is beslissen welke klassen ze moeten maken en hoe ze het werk onder hen moeten verdelen."
"Hoe meer ze dergelijke vragen oplosten, hoe meer ze beseften dat sommige oplossingen goed zijn en andere slecht."
"Slechte oplossingen creëren meestal meer problemen dan ze oplossen. Ze breiden slecht uit, creëren veel onnodige beperkingen, enz. En goede oplossingen zijn het tegenovergestelde."
"Is er een analogie die je kunt maken?"
"Stel dat je een huis bouwt. En je bedenkt waar het van gemaakt zal worden. Je besluit dat je muren, een vloer en een plafond nodig hebt. Het resultaat is dat je een huis bouwt met een plat dak en geen fundering. Zo'n huis barst en het dak gaat lekken. Dit is een slechte oplossing."
“Omgekeerd zou een huis bestaande uit een fundering, muren en een zadeldak een goede oplossing zijn. Hevige sneeuwval is geen probleem, want de sneeuw glijdt zo van het dak. stabiliteit. We zouden zo'n oplossing goed noemen."
"Ik begrijp het. Bedankt."
"Oké. Dan ga ik verder."
"Na verloop van tijd werden de goede oplossingen bekend als ontwerppatronen, terwijl de slechte antipatronen werden genoemd."
"Een ontwerppatroon is als een antwoord op een vraag. Het is moeilijk te begrijpen als je de vraag nog nooit hebt gehoord."
" De eerste categorie patronen zijn creatiepatronen. Dergelijke patronen beschrijven goede oplossingen met betrekking tot het creëren van objecten."
"Wat is er zo ingewikkeld aan het maken van objecten?"
"Toevallig is dat precies wat we nu gaan onderzoeken."
Singleton-patroon.
"Vaak kan in programma's slechts één enkele kopie van sommige objecten bestaan. Bijvoorbeeld de console, logger, vuilnisman, enz."
" Slechte oplossing: maak geen objecten - maak gewoon een klasse waarvan de methoden allemaal statisch zijn."
" Goede oplossing: maak een enkel object en sla het op in een statische variabele. Voorkom dat er een tweede object van de klasse wordt gemaakt. Bijvoorbeeld:"
class Sun
{
private static Sun instance;
public static Sun getInstance()
{
if (instance == null)
instance = new Sun();
return instance;
}
private Sun()
{
}
}
Sun sun = Sun.getInstance();
"Het is makkelijk."
"Eerst maken we de constructor privé. Nu kan hij alleen worden aangeroepen vanuit onze klasse. We hebben het maken van Sun-objecten overal geblokkeerd, behalve binnen methoden van de Sun-klasse."
"Ten tweede kan een object van deze klasse alleen worden verkregen door de methode getInstance() aan te roepen. Dit is niet alleen de enige methode die een Sun-object kan maken, het zorgt er ook voor dat er maar één zo'n object is."
"Ik zie."
"Als je denkt: "Hoe moet ik dat nu precies doen?", zegt een patroon, "je kunt dit proberen - dit is een van de beste oplossingen."
"Bedankt. Nu beginnen dingen duidelijk te worden."
"Je kunt hier ook over dit patroon lezen ."
Fabrieks patroon.
"Dit is een situatie waar programmeurs heel vaak mee te maken hebben. Je hebt een basisklasse en veel subklassen. Bijvoorbeeld een spelkarakterklasse (GamePerson) en klassen voor alle andere karakters die deze overerven."
"Stel dat je de volgende klassen hebt:"
abstract class GamePerson
{
}
class Warrior extends GamePerson
{
}
class Mag extends GamePerson
{
}
class Troll extends GamePerson
{
}
class Elf extends GamePerson
{
}
"De vraag is hoe we flexibel en gemakkelijk de creatie van objecten van deze klassen kunnen beheren."
"Als dit probleem je vergezocht lijkt, stel je dan voor dat je in het spel tientallen zwaarden en schilden, honderden magische spreuken en duizenden monsters moet maken. Je kunt hier niet zonder een handige benadering om objecten te maken. "
"Het Factory- patroon biedt een goede oplossing."
"Eerst moeten we een opsomming maken waarvan de waarden overeenkomen met de verschillende klassen."
"Ten tweede, maak een speciale Factory- klasse met statische methode(n) die object(en) maken op basis van een opsommingswaarde."
"Bijvoorbeeld:"
public enum PersonType
{
UNKNOWN,
WARRIOR,
MAG,
TROLL,
ELF,
}
public class PersonFactory
{
public static GamePerson createPerson(PersonType personType)
{
switch(personType)
{
WARRIOR:
return new Warrior();
MAG:
return new Mag();
TROLL:
return new Troll();
ELF:
return new Elf();
default:
throw new GameException();
}
}
}
GamePerson person = PersonFactory.createPerson(PersonType.MAG);
"Met andere woorden, we hebben een speciale klasse gemaakt om het maken van objecten te beheren?"
"Ja."
"Dus welke voordelen biedt dit?"
"Ten eerste kunnen in deze klasse de objecten worden geïnitialiseerd met de benodigde gegevens."
"Ten tweede kun je de benodigde enum-waarde zo vaak doorgeven tussen methoden om uiteindelijk het gewenste object te creëren."
"Ten derde hoeft het aantal enum-velden niet overeen te komen met het aantal klassen. Er kunnen veel soorten karakters zijn, maar weinig klassen."
"Een Mag & Warrior kan bijvoorbeeld één klasse gebruiken (Human), maar met verschillende sterkte- en magische eigenschappen (constructorargumenten)."
"Dit is hoe het eruit zou kunnen zien (voor de duidelijkheid, ik heb ook donkere elven toegevoegd):"
public enum PersonType
{
UNKNOWN,
WARRIOR,
MAG,
TROLL,
ELF,
DARK_ELF
}
public class PersonFactory
{
public static GamePerson createPerson(PersonType personType)
{
switch(personType)
{
WARRIOR:
return new Human(10, 0); // Strength, magic
MAG:
return new Human(0, 10); // Strength, magic
TROLL:
OGR:
return new Troll();
ELF:
return new Elf(true); // true – good, false – evil
DARK_ELF:
return new Elf(false); // true – good, false – evil
default:
throw new GameException();
}
}
}
GamePerson person = PersonFactory.createPerson(PersonType.MAG);
"In het bovenstaande voorbeeld hebben we slechts drie klassen gebruikt om zes verschillende soorten objecten te maken. Dit is erg handig. Bovendien hebben we al deze logica geconcentreerd in één klasse en één methode."
"Stel nu dat we besluiten een aparte klasse voor Ogre te maken - we veranderen hier gewoon een paar regels code, en niet de helft van de applicatie."
'Ik ben het ermee eens. Dat is een goede oplossing.'
"En daar heb ik het over: ontwerppatronen zijn verzamelingen van goede oplossingen."
"Ik wou ook dat ik wist waar ik ze moest gebruiken..."
"Ja. Mee eens, je zult het niet meteen begrijpen. Toch is het beter om te weten en niet te kunnen dan om niet te weten en niet te kunnen. Hier is nog een handige link voor je over dit patroon: Fabriekspatroon "
"Oh bedankt."
" Abstract fabriekspatroon ."
"Soms als je veel objecten hebt, komt het idee om een fabriek voor fabrieken te maken vanzelf op. Zo'n fabriek wordt een abstracte fabriek genoemd ."
"Waar zou dit nodig zijn?!"
"Stel dat je meerdere groepen identieke objecten hebt. Met een voorbeeld is dat makkelijker aan te tonen."
"Laten we nu zeggen dat je drie rassen in je spel hebt: mensen, elven en demonen. En voor het evenwicht heeft elk ras krijgers, boogschutters en magiërs. Een speler kan alleen objecten maken die behoren tot het ras waarvoor hij of zij speelt in het spel. Zo ziet het eruit in code:"
class Warrior
{
}
class Archer
{
}
class Mag
{
}
class HumanWarrior extends Warrior
{
}
class HumanArcher extends Archer
{
}
class HumanMag extends Mag
{
}
class ElfWarrior extends Warrior
{
}
class ElfArcher extends Archer
{
}
class ElfMag extends Mag
{
}
class DaemonWarrior extends Warrior
{
}
class DaemonArcher extends Archer
{
}
class DaemonMag extends Mag
{
}
En laten we nu de rassen creëren, of we zouden ze ook legers kunnen noemen.
abstract class Army
{
public Warrior createWarrior();
public Archer createArcher();
public Mag createMag();
}
class HumanArmy extends Army
{
public Warrior createWarrior()
{
return new HumanWarrior();
}
public Archer createArcher()
{
return new HumanArcher();
}
public Mag createMag()
{
return new HumanMag();
}
}
class ElfArmy extends Army
{
public Warrior createWarrior()
{
return new ElfWarrior();
}
public Archer createArcher()
{
return new ElfArcher();
}
public Mag createMag()
{
return new ElfMag();
}
}
class DaemonArmy extends Army
{
public Warrior createWarrior()
{
return new DaemonWarrior();
}
public Archer createArcher()
{
return new DaemonArcher();
}
public Mag createMag()
{
return new DaemonMag();
}
}
"Maar hoe gebruik je dit?"
"Je kunt de klassen Army, Warrior, Archer en Mage overal in het programma gebruiken en om de benodigde objecten te maken, geef je gewoon een object van de gewenste Army-subklasse door."
"Bijvoorbeeld:"
Army humans = new HumanArmy();
Army daemons = new DaemonArmy();
Army winner = FightSimulator.simulate(humans, daemons);
"In het bovenstaande voorbeeld hebben we een klasse die gevechten tussen verschillende rassen (legers) simuleert. Je hoeft alleen maar twee legerobjecten te passeren. De klasse gebruikt ze zelf om verschillende troepen te creëren en voert virtuele gevechten tussen hen uit om de overwinnaar te identificeren ."
"Ik begrijp het. Bedankt. Een heel interessante benadering."
"Een goede oplossing, ongeacht wat je zegt."
"Ja."
"Hier is nog een goede link over het onderwerp: Abstract fabriekspatroon "
GO TO FULL VERSION