Svar och lösningar till tentan på DD2385 26 maj 2009. ===================================================== del I ----- En del av svaren på del I är ganska långa. Ett mindre utförligt svar duger ofta för att få full poäng. 1) Svår att skriva bra här. 2) Om man växlar mellan olika spelalgoritmer under körning av ett program så är det mönstret Strategy som ligger närmast till hands. Även State gav poäng. 3) Uppgiften beskriver en variant av "bankomat-problemet". Det är två trådar som samtidigt tillåts uppdatera en variabel. De kan inte exekvera riktigt samtidigt utan får turas om och göra en bit i taget av sin uppgift. Om uppdateringen av stegsummavariabeln oturligt sker på så sätt att den ena tråden läser av ursprungsvärdet men inte hinner lägga tillbaka den nya summan innan den andra tråden läser av startvärdet så kommer båda trådarna att ge summavariabeln gamla värdet + 14300. Lösningen på problemet är att se till att den första tråden får räkna klart innan den andra börjar. Då får man två uppräkningar med vardera 14300, alltså +28600. Uppdateringen av steg-variabeln görs förstås i en metod. Märk den metoden med synchronized så är problemet löst! 4) Decorator - D, Mediator - C, Proxy - B 5 a) Observer 5 b) När Observer beskrivs används termerna Observable (eller Subject) samt Observers. EN Observable underrättar n st Observers när något ändrats i tillståndet hos Observable. Varje grafisk komponent med lyssnare är en Observable. De inkopplade lyssnarna är Observers. När något händer i den grafiska komponenten (t.ex. tryck på en knapp) så underrättas alla lyssnare. I mönstret beskrivs en metod update(). Denna motsvaras av lyssnarmetoderna, t.ex. actionPerformed (...) i ActionListener. 6) Vattenfall: A och C, XP: B och D 7) B 8) A 9) B) De första och tredje metodanropen är självklara: Person -> Vila och Motionär -> Träna. Person samanta = new Motionär(); Är det aktivitet för Person eller aktivitet för Motionär som anropas vid samanta.aktivitet() ? Det är objektets typ och inte referensens typ som avgör vilken metod som anropas. Alltså är det Motionärens aktivitet som gäller och utskriften blir "Träna". 10) Enklaste lösningen (men flera alternativ finns) är att införa ett interface som A är beroende av och som B får implementera. Det är "lösare" att bero av ett interface än en klass med implementerade metoder. class A { BI minB; ..... } interface BI { // skriv huvuden för alla metoder som B ska ha } class B implements BI { // implementera alla metoder som står i BI } 11) JUnit används för testning. Svar: D del II ------ 12) Det är ganska stor variation på lösningar som ger full poäng. Det är en skissartad lösning som efterfrågas. En del detaljer återstår att lösa innan det blir en körbar komponent. 12 a) Eftersom komponenten ärver från Canvas eller JPanel kan den inte dessutom ärva från Thread utan måste istället implementera gränssnittet Runnable. "implements Runnable" är de två ord som frågas efter. 12 b) Stjärobjekten är redan skapade och finns i listan allStars. Komponenten måste ha en metod run() vare sig den ärver från Thread eller implementerar Runnable. Det är denna metod som definierar vad komponenten ska göra: Här är det att med något litet tidsintervall rita om stjärnhimlen och variera stjärdiametrarna hos ca 20% av stjärnorna. Run-metoden innehåller ingen automatisk upprepning utan man måste själv skriva en sådan. while(true) .... är det simplaste sättet. public void run() { while (true) { try{ Thread.sleep(50); // vänta en stund } catch (InterruptedException e) {...} // *** anropa metod som "mörkar" himlen **** for (Star s : allStars) { if (Math.random() > 0.8) { // väljer ut ca 20% av s.changeDiameter() // stjärnorna } s.draw(); // rita alltid } } } Någon metod som målar hela himlen mörk bör anropas innan man ritar om stjärnorna. Denna behövde man INTE ange för att få full poäng, inte heller try...catch omkring Thread.sleep. Ritande i Java-komponenter görs vanligen i en metod paint(...) eller paintComponent(...) som ärvs och definieras om. I en riktig komponent bör man använda någon av dessa metoder för omritning men det krävs inte heller i uppgiften. 12 c) Mönstret heter Template Method. Tomma metoder definieras t.ex. i grundversionen av Sky. I en subklass, t.ex. ColorSky definieras icke-tomma metoder med samma namn. ColorSky ärver allt som finns i Sky men kan definiera sitt eget tillägg till tindrandet. 12 d) Koppla en lyssnare till hela komponenten. Enklast genom att klassen Sky får implementera ActionListener. Inför en boolesk variabel som håller reda på om tindrandet är av eller på. Använd den booleska variabeln i run()-metoden för att styra om change-diameter (och ev. även omritning) ska ske. class Sky extends JPanel implements Runnable, ActionListener { boolean twinkle = true; public Sky () { // Här i konstruktorn kopplas addActionListener(this); // komponenten som lyssnare } // till sig själv public void actionPerformed (ActionEvenet e) { twinkle = !twinkle; // ändra från true till false eller // från false till true } public void run () { : if (twinkle) { if (Math.random() > 0.8) { s.changeDiameter(); } } : } 12 e) UML-lösningen som konstrueras måste stämma med den EGNA lösningen på uppgifterna a)-d). 13 a) Medel Skivstång Spinning Medel Medel 13 b) * betyder 0 eller flera, + betyder en eller flera.