"Hej, Amigo!"
"Hej, Bilaabo!"
"Vårt ämne idag kommer inte bara att vara intressant - det kommer att vara rent episkt."
"Idag kommer jag till dig vad designmönster är. "
"Coolt! Jag har hört mycket om dem. Jag kan inte vänta!"
"Erfarna programmerare måste skriva många klasser. Men den svåraste delen av det här jobbet är att bestämma vilka klasser som ska skapas och hur de ska fördela arbetet mellan dem."
"Ju mer de löste sådana frågor, desto mer insåg de att vissa lösningar är bra, medan andra är dåliga."
"Dåliga lösningar skapar oftast fler problem än de löser. De sträcker sig dåligt, skapar många onödiga begränsningar etc. Och bra lösningar är motsatsen."
"Finns det någon analogi du kan göra?"
"Låt oss säga att du bygger ett hus. Och du tänker på vad det ska vara gjort av. Du bestämmer dig för att du behöver väggar, ett golv och ett tak. Som ett resultat bygger du ett hus med platt tak och inget grund. Ett sådant hus kommer att spricka, och taket kommer att läcka. Det här är en dålig lösning."
"Omvänt skulle ett hus bestående av en grund, väggar och ett sadeltak vara en bra lösning. Kraftigt snöfall utgör inga problem, eftersom snön kommer att glida av taket. Och skiftande jordar är inget att frukta, eftersom grunden kommer att säkerställa stabilitet. Vi skulle kalla en sådan lösning bra."
"Jag förstår. Tack."
"OK. Då fortsätter jag."
"Med tiden kom de bra lösningarna att kallas designmönster, medan de dåliga kallades antimönster."
"Ett designmönster är som ett svar på en fråga. Det är svårt att förstå om du aldrig har hört frågan."
" Den första kategorin av mönster är skapande mönster. Sådana mönster beskriver bra lösningar relaterade till skapandet av objekt."
"Vad är det som är så komplicerat med att skapa objekt?"
"Som det händer, det är precis vad vi ska utforska nu."
Singleton mönster.
"Ofta i program kan bara en enda kopia av vissa objekt existera. Till exempel konsolen, loggern, sophämtaren, etc."
" Dålig lösning: skapa inga objekt - skapa bara en klass vars metoder alla är statiska."
" Bra lösning: skapa ett enda objekt och lagra det i en statisk variabel. Förhindra skapandet av ett andra objekt i klassen. Till exempel:"
class Sun
{
private static Sun instance;
public static Sun getInstance()
{
if (instance == null)
instance = new Sun();
return instance;
}
private Sun()
{
}
}
Sun sun = Sun.getInstance();
"Det är enkelt."
"Först gör vi konstruktorn privat. Nu kan den bara anropas inifrån vår klass. Vi har blockerat skapandet av Sun-objekt överallt förutom inom metoderna i Sun-klassen."
"För det andra kan ett objekt av den här klassen endast erhållas genom att anropa metoden getInstance(). Detta är inte bara den enda metoden som kan skapa ett Sun-objekt, den säkerställer också att det bara finns ett sådant objekt."
"Jag förstår."
"När du tänker, "Nu, hur exakt skulle jag göra det?", säger ett mönster, "du kan prova det här - det här är en av de bästa lösningarna."
"Tack. Nu börjar det bli klart."
"Du kan också läsa om det här mönstret här ."
Fabriksmönster.
"Här är en situation som programmerare möter väldigt ofta. Du har en viss basklass och många underklasser. Till exempel en spelkaraktärsklass (GamePerson) och klasser för alla andra karaktärer som ärver den."
"Låt oss säga att du har följande klasser:"
abstract class GamePerson
{
}
class Warrior extends GamePerson
{
}
class Mag extends GamePerson
{
}
class Troll extends GamePerson
{
}
class Elf extends GamePerson
{
}
"Frågan är hur vi flexibelt och bekvämt hanterar skapandet av objekt av dessa klasser."
"Om det här problemet verkar långsökt för dig, föreställ dig att du i spelet behöver skapa dussintals svärd och sköldar, hundratals magiska besvärjelser och tusentals monster. Du kan inte klara dig utan ett bekvämt tillvägagångssätt för att skapa objekt här. "
" Fabriksmönstret erbjuder en bra lösning."
"Först måste vi skapa en uppräkning vars värden motsvarar de olika klasserna."
"För det andra, skapa en speciell Factory- klass som har statiska metoder som skapar objekt baserat på ett uppräkningsvärde."
"Till exempel:"
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);
"Med andra ord, vi skapade en speciell klass för att hantera objektskapande?"
"Japp."
"Så vilka fördelar ger detta?"
"För det första, i den här klassen kan objekten initieras med nödvändig data."
"För det andra kan du skicka det nödvändiga enumvärdet mellan metoderna så mycket du vill för att i slutändan skapa det önskade objektet."
"För det tredje behöver antalet uppräkningsfält inte matcha antalet klasser. Det kan finnas många typer av tecken, men få klasser."
"Till exempel kan en Mag & Warrior använda en klass (Human), men med olika styrka och magiska egenskaper (konstruktorargument)."
"Så här kan det se ut (för tydlighetens skull har jag även lagt till mörka tomtar):"
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);
"I exemplet ovan använde vi bara tre klasser för att skapa sex olika typer av objekt. Detta är väldigt bekvämt. Dessutom har vi all denna logik koncentrerad i en klass och en metod."
"Anta nu att vi bestämmer oss för att skapa en separat klass för Ogre - vi ändrar helt enkelt ett par rader kod här, och inte halva applikationen."
"Jag håller med. Det är en bra lösning."
"Och det är vad jag pratar om: designmönster är samlingar av bra lösningar."
"Jag önskar också att jag visste var jag skulle använda dem..."
"Japp. Jag håller med, du kommer inte att förstå direkt. Ändå är det bättre att veta och inte kunna göra än att inte veta och inte kunna göra. Här är en annan användbar länk för dig om det här mönstret: Factory Pattern "
"Åh, tack."
" Abstrakt fabriksmönster ."
"Ibland när man har många föremål kommer idén att skapa en fabrik för fabriker upp sig själv. En sådan fabrik kallas en abstrakt fabrik ."
"Var skulle detta behövas?!"
"Anta att du har flera grupper av identiska föremål. Detta är lättare att visa med ett exempel."
"Låt oss nu säga att du har tre raser i ditt spel: människor, alver och demoner. Och för balansen har varje ras krigare, bågskyttar och magiker. En spelare kan bara skapa föremål som tillhör rasen han eller hon spelar för i spelet. Så här skulle det se ut i koden:"
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
{
}
Och låt oss nu skapa raserna, eller så kan vi också kalla dem arméer.
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();
}
}
"Men hur använder du det här?"
"Du kan använda klasserna Army, Warrior, Archer och Mage var som helst i programmet, och för att skapa de nödvändiga objekten - passera helt enkelt ett objekt av den önskade Army-underklassen."
"Till exempel:"
Army humans = new HumanArmy();
Army daemons = new DaemonArmy();
Army winner = FightSimulator.simulate(humans, daemons);
"I exemplet ovan har vi en klass som simulerar strider mellan olika raser (arméer). Du behöver bara passera två arméobjekt. Klassen själv använder dem för att skapa olika trupper och genomför virtuella strider mellan dem för att identifiera segraren ."
"Jag förstår. Tack. Ett riktigt intressant tillvägagångssätt."
"En bra lösning, oavsett vad du säger."
"Japp."
"Här är en annan bra länk om ämnet: Abstrakt fabriksmönster "
GO TO FULL VERSION