Exempel: Kontrollsystem för uppvärmning

Sven-Olof Nyström
OOP med Java våren -25
Informationsteknologi
Uppsala Universitet

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.

Kontrollsystemet i stort.

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.

Intelligens

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.

Värmepannan

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.

Hur löser man detta?

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.

Hur hittar vi lämpliga klasser?

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.

En andra ansats

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, några komplikationer

Om 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?

(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.

En lösning:

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.

Insikter...

Värmesystem, forts

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.

Närvaro

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

Var placera kod som hanterar närvaro?

Notera att:

En viktig princip: En klass bör inte arbeta med två komplexa, orelaterade problem.

Närvaro, lösningsalternativ

Tre alternativ:

  1. Varje rum hanterar sin egen närvaro
  2. för varje rum finns ett närvaro-objekt som hanterar närvaron för detta objekt
  3. ett objekt "närvaro", gemensamt för alla rum

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.

Värmesystem, klasser

Ett lösningsförslag:

Värmesystem, kommentar

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.