Lösningar till Fiktiv Tentamen på kursen 2D4135 Objektorienterad programmering, design och analys med Java vt2004 Teoridel T1) (4p) Förklara kort följande grundläggande begrepp inom objektorienterad programmering: a) Klass b) Instans c) Arv d) Inkapsling a) En beskrivning av data (variabler) och beteende (metoder) för en samling liknande objekt. En mall för hur objekt ska se ut. b) Ett objekt skapat från en mall/ritning, mallen utgörs av en klass. c) En klass kan definieras som en påbyggnad (subklass) på en annan klass (superklass). Den ärvande klassen har alla attribut och metoder som superklassen utan att dessa måste definieras om. d) Att gömma vissa data och vissa metoder inuti en klass så att den som använder klassen inte ser eller kommer åt dem. T2 (2p) a)vad menas med att en klass är abstrakt (abstract i Java) respektive att en metod är abstrakt? En abstrakt klass kan/får inte instansieras, den innehåller minst en metod som är abstrakt. En abstrakt metod har ingen metodkropp, endast metodhuvud med returtyp och parametertyper. Metoden definieras fullständigt i en subklass. b) Vad använder man abstrakta klasser till inom objektorienterad programmering? Ge gärna ett exempel (helst utan programkod), det krävs dock inte. En abstrakt klass används som en basklass från vilken andra klasser ärver. Klasserna kan ha en gemensam del (både variabler och metoder) och en del som skiljer men måste finnas med för att klasserna ska bli meningsfulla. Då definieras den gemensamma delen i en abstrakt klass och de åtskiljande delarna i konkreta subklasser. 1
T3a (2p)Vadmenasmedmultipeltarv?Beskiviordienmeningochritaett UML-diagram. Att en klass A B ärver direkt från två (eller flera) /_\ /_\ andra klasser C b) Vissa OO-språk, t.ex. Java har inte multipelt arv. Då kan man använda s.k. komposition i stället. Beskriv denna teknik. Här beskrivs komposition med två klasser, man kan förstås ha fler än två. Man låter ett objekt av klassen C bestå av ett objekt av klassen A och ett objekt av klassen B samt ev. tillägg. När en instans av C skapas så skapas (oftast i C:s konstruktor) en instans av vardera A och B. Publika metoder i A resp. B blir ju inte direkt åtkomliga utan måste definieras om. Antag både A och B har var sin metod m: class C { A mya; B myb; C (... ) { mya = new A(... ); myb = new B(... ); void ma (... ) { mya.m(); void mb (... ) { myb.m(); T4 (2p) a) Förklara kort vad designmönster är. Ett designmönster är en beprövad lösning på ett OO-programmeringsproblem som återkommer i flera sammanhang. Ett designmönster har ett namn, vissa mönster flera namn. Mönster brukar beskrivas enligt en mall med med UML-klassdigagram, syfte, användningsområde samt presentation av de ingående komponenterna och deras roll i mönstret. b) Nämn minst två fördelar med att använda designmönster. Ger programmerare (programdesigners) en mer kraftfull vokabulär vid diskussioner. Designmönstren är samlad, väl utprovad expertkunskap som fungerar (men man måste förstås programmera rätt). Kan förenkla underhåll av program om man anger vilka mönster som används och underhållaren har kunskap om dessa. 2
T5) C T10) B T6) C T11) C T7) A T12) D T8) D T13) C T9) B T14) B T14 Objektets typ (inte referensvariabelns) bestämmer vilken metod som anropas. P1 ) Problemdel 1 0..* Skola -------------- Student 1 0..* 0..* 1..* i-------------- Kurs 1..* 1..* 1..* 1 Avdelning ----------- Lärare 1 /_\ 1 i---------------- Chefslärare Det stod inget i uppgiften om relationen mellan Kurs och Lärare. 3
P2a) I lösningen nedan skapas alla instanserna från början. Ett annat alternativ är att en instans skapas då den efterfrågas första gången. public class Dvarg { // static-del public final static String[] NAMN = {"Blyger", "Butter", "Glader", "Kloker", "Prosit", "Toker","Trötter"; public final static int N = 7; private static Dvarg[] theinstance = new Dvarg[7]; static { // initieringsblock for (int i=0; i<n; i++) theinstance[i] = new Dvarg(NAMN[i]); public static Dvarg getdvarg (int i) { if (i<0 i>=n) return null; return theinstance[i]; // instans-del private String namn; private Dvarg (String n) { namn = n; public String tostring () { return "Jag är " + namn; // Fler instansvariabler och instansmetoder som beskriver // dvärgens egenskaper och beteende. P2b) Variabeln N får sättas av metoden setnumber(..), men bara en gång. En boolesk variabel kan hålla reda på om det är gjort eller ej (alternativt kan man avända N == 0 som test. Instanserna kan skapas då N sätts eller då de efterfrågas. Om en instans efterfrågas innan N har fått värde returneras null och/eller felmeddelande. 4
P3a) class Stad { private String namn; private int antalinv; Stad (String na, int n) { namn = na; antalinv = n; public String tostring() { return namn + " har " + antalinv + " invånare."; class Residensstad extends Stad { private String landshovding; Residensstad (String na, int n, String l) { super(na, n); landshovding = l; public String tostring() { return super.tostring() + " Residensstad, landshövding är " + landshovding + "."; class Stiftsstad extends Stad { private String biskop; Stiftsstad (String na, int n, String b) { super(na, n); biskop = b; public String tostring() { return super.tostring() + " Stiftsstad, biskop är " + biskop + "."; P3b) Dynamisk (metod) bindning. Svaret polymorfism skulle också gett en poäng. P3c) Nej,Stad kan inte vara abstrakt. Då kan man inte instansiera städer som varken är stiftsstad eller residensstad. 5
P3d) En klass i Java kan inte ärva direkt från mer än en klass men den kan implementera flera interface. Man kan göra ett interface för typen Stiftsstad, t.ex. StiftsstadI och låta både Stiftsstad och StiftsOchResidensstad implementera detta. Klassen StiftsOchResidensstad ärver dessutom från Residensstad. På så sätt åstadkommer man att typen Residensstad kan användas för residensstäder och stiftsochresidensstäder och typen StiftsstadI kan användas för både stiftsstäder och stiftsochresidensstäder. En annat variant på detta problem som inte uppfyller de krav på typer som ställs i uppgiften är att använda designmönstret Decorator för att dekorera städer med stiftsstad och/eller residensstad. P4a) import java.awt.*; import java.awt.event.*; import java.util.*; class Salong extends Panel implements ActionListener { Button[][] plats; int n, m; Label rubrik; Color freecolor = Color.green, bookedcolor = Color.red; Salong (String namn, int n, int m) { this.n = n; this.m = m; rubrik = new Label(namn); setlayout(new BorderLayout()); Panel platser = new Panel(); add(rubrik, BorderLayout.NORTH); platser.setlayout(new GridLayout(n,m)); plats = new Button[n][m]; for (int i=0; i< plats.length; i++) for (int j=0; j< plats[i].length; j++) { Button p = new Button(); p.setbackground(freecolor); platser.add(p); p.addactionlistener(this); plats[i][j] = p; numrera(); add(platser, BorderLayout.CENTER); // Klassen Salong fortsätter på nästa sida 6
// fortsättning på Salong private void numrera () { int nummer = 1; for (int rad = n-1; rad >= 0; rad--) if (rad % 2 == 0) for (int kol = 0; kol<m; kol++) plats[rad][kol].setlabel("" + nummer++); else for (int kol = m-1; kol>=0; kol--) plats[rad][kol].setlabel("" + nummer++); public void actionperformed (ActionEvent e) { changecolor( (Button)e.getSource() ); void changecolor(button b) { if (b.getbackground().equals(bookedcolor)) b.setbackground(freecolor); else b.setbackground(bookedcolor); Numreringen av knapparna görs nerifrån och upp, börjar på rad n-1 och forsätter uppåt till rad 0. Varannan rad (de med jämnt nummer) numreras från vänster till höger och varannan från höger till vänster. Metoden numrera har väldigt lite måsvingeparanteser trots flera nivåer av nästlade for och if satser. Det är fullt tillåtet att ha fler måsvingar för tydlighetens skull! P4b) import java.awt.*; class TestaSalong extends Frame { Salong salong; TestaSalong () { setlayout(new FlowLayout()); setsize(500, 300); setbackground(color.white); Salong stora = new Salong ("Stora salongen", 7, 10); add(stora); Salong lilla = new Salong ("Lilla Salongen", 3, 4); add(lilla); setvisible(true); public static void main (String[] s) { new TestaSalong(); 7