Det här exemplet är lånat från Booch: Object-oriented Design With Applications. Jag kommer inte att ge en detaljerad lösning. Här är det viktiga inte den färdiga lösningen utan processen som tar oss dit.
Nej, så här fungerar inte värmesystem (åtminstone inte i Sverige).
I detta exempel är objektstrukturen statisk—vi skapar aldrig nya objekt.
Ett kontrollsystem för uppvärmning av ett hus. Vi har följande komponenter:
Användargränssnitt
Här ställer man in önskad temperatur för varje rum. Även annan interaktion implementeras här, till exempel metoder för att övervaka och styra pannan.
Temperaturgivare
Varje rum har en temperaturgivare som ger oss rummets temperatur.
Värmeledningsventil
Varje rum har en värmeledningsventil. Den kan öppnas för att släppa på värme.
Timer
En timer som hjälper systemet hålla reda på tid.
Sensor
Vi vill kunna avgöra om någon befinner sig i ett av rummen. Detta kan lösas med antingen en infraröd sensor eller en rörelsesensor i varje rum.
Värmepanna
Värmepannan producerar värme som distribueras till rummen via ett vattenburet system. När ett visst rum behöver värme ska värmepannan slås på och ventilen till det rummet öppnas.
Om ett rum används (det finns nån där) ska temperaturen vara enligt önskad temp (+/- 2F). Om rummet ej används accepteras en något lägre temperatur (5 fahrenheit eller 2.8 C lägre)
Systemet försöker att förutse människornas beteende genom att komma ihåg hur rummen har använts tidigare. Om systemet tror att ett rum kommer att befolkas inom 30 minuter höjs temperaturen.
Systemet använder enkel regel för att förutse hur olika rum kommer att användas: En databas lagrar det förväntade levnadsmönstret under en vecka samt rumsanvändningen två veckor bakåt i tiden. Om det förväntade levnadsmönstret bryts två veckor i rad uppdateras databasen med det nya beteendet.
Kontrollen av pannan är komplex. En korrekt uppstart kräver att fläkt, oljepump och tändning startas i viss ordningsföljd och med visst tidsintervall.
Om pannan stoppats måste det ta minst 5 minuter innan den startas igen, annars kan pannan skadas.
Pannan startas när minst ett rum behöver värme.
En naturlig lösning är att skapa klasser utgående från figuren ovan.
Med denna lösning får vi en komplex klass (Heat-flow regulator), medan övriga blir mycket enkla.
Detta är ett utmärkt exempel på dålig OOP! Lösningen lägger hela ansvaret på en klass.
Det finns några strategier för att hitta lämpliga klasser. Man kan till exempel
Vi måste förenkla problemet—klasstrukturen bör ge ledning i hur man bryter ner uppgiften i naturliga delproblem.
Ge klassen Furnace två metoder:
void setRunning(boolean b); boolean getRunning();
Klassen Furnace
implementerar
När vi vill starta pannan skickar vi meddelandet setRunning(true)
till
pannan, och när den ska stanna skickar vi setRunning(false)
.
Denna ansats har några fördelar:
Furnace
får ett enklare gränssnittOm pannan just stängts av och setRunning(true)
anropas, vad ska
Furnace
göra?
Ska getRunning()
returnera true
eller false
när du väntar?
true
, det är mera konsistent med hur get
och set
förväntas fungerafalse
, annars ljuger vi(Fundera lite på de här frågorna innan du läser vidare.)
Om Furnace
inte implementerar 5-minutersregeln måste alla objekt som
kommunicerar med Furnace
implementera regeln. Detta innebär i
praktiken att 5-minutersregeln blir en del av gränssnittet för
klassen Furnace
.
Kalla metoderna nåt annat, tex
void setHeatRequired(boolean b) boolean getHeatRequired();
Metoden getHeatRequired()
kan förstås returnera true
även om pannan
står stilla. Ansvaret för att implementera 5-minutersregeln faller
nu på klassen Furnace
.
Idé: inför en klass Rum. Varje rum håller reda på
Vilket ansvar återstår för värmeflödesregulatorn?
Nu har den centrala värmeflödesregulatorn en enkel uppgift: Om minst ett rum behöver värme, tala om det för pannan.
Ett rum ska betraktas som "i bruk" om antingen
Det är antagligen lämpligt att införa en abstraktion "närvaro" som täcker båda fallen
Notera att:
En viktig princip: En klass bör inte arbeta med två komplexa, orelaterade problem.
Tre alternativ:
Jag skulle rösta på att koppla närvaro till rummen, dvs första eller andra alternativet.
Om närvarohanteringen är komplex läggs den lämpligtvis i en separat klass, dvs alternativ 2 eller 3.
Ett lösningsförslag:
Ett system är lättare att förstå om varje klass inte är alltför komplicerad.
Ibland är det lämpligt att introducera abstraktioner (I detta fall: "närvaro").
Val av namn på klasser och metoder kan vara viktigt.
I problemspecifikationen är hantering av närvaro överspecificerad. Man kan tänka sig många olika strategier för att förutse hur rum kommer att användas. För att avgöra vilken strategi som fungerar bäst i praktiken krävs experiment.
Det är inte så lyckat att binda sig för en typ av panna; specifikationen borde även här ha sett annorlunda ut.