Objektorienterad modellering och design (EDAF25) Föreläsning 3 UML Objektdiagram Agenda UML objekt och sekvensdiagram Design smells Designprinciper (ALP, SRP, OCP, DIP) (, Composite) Att göra denna och nästa vecka: Frivillig laboration Eclipse/UML Handledning erbjuds på fredag! Läs Martin 13,14 och 23 Lös uppgifterna till övning1 Redovisas nästa fredag 27:e februari! EDAF25 (F3) VT 2015 1 / 50 UML Objektdiagram EDAF25 (F3) VT 2015 2 / 50 UML Sekvensdiagram (1+2) + 3 EDAF25 (F3) VT 2015 3 / 50 EDAF25 (F3) VT 2015 4 / 50
UML Sekvensdiagram Aktivitet UML Sekvensdiagram (1+2) + 3 Visa beräkning av (1 + 2) + 3 i ett sekvensdiagram. EDAF25 (F3) VT 2015 5 / 50 UML Sekvensdiagram Martin EDAF25 (F3) VT 2015 6 / 50 Principles, Patterns, and Practices EDAF25 (F3) VT 2015 7 / 50 EDAF25 (F3) VT 2015 8 / 50
Design smells Design smells Design smells Stelhet (Rigidity) Designen är svår att modifiera Bräcklighet (Fragility) Designen tål inte modifiering Orörlighet (Immobility) Designen förhindrar återanvändning Seghet (Viscosity) Det är svårare att göra snygga ändringar än "hack" Spekulativ design (Needless Complexity) Duplicerad kod (Needless Repetition) Klipp & klistra-orienterad programmering Onödiga getters (Needless Getters) Brott mot ALP Oklarhet (Opacity) Obegriplig design EDAF25 (F3) VT 2015 9 / 50 Agil design EDAF25 (F3) VT 2015 10 / 50 Designprinciper Exempel i Martin s.90-94 "Kopieringsprogrammet" Agil praxis -> Identifikation av ett problem Designprinciper -> Diagnosticering av problemen -> Lösning av problemet ALP Lokalitetsprincipen SRP Single Responsibilty Principle OCP Open/Closed Principle DIP Dependency Inversion Principle LSP Liskov Substitution Principle (kommer senare) ISP Interface Segregation Principle (kommer senare) EDAF25 (F3) VT 2015 11 / 50 EDAF25 (F3) VT 2015 12 / 50
Exempel på dålig design Fortfarande dålig public class CompetitionHandler { // or TotalComputation private Competition competition; starttime = competition.getraces()[i].getresults()[j]. getstarttime().getseconds(); endtime = competition.getraces()[i].getresults()[j]. getendtime().getseconds(); competition.getraces()[i].getresults()[j].getresults()[j]. settotaltime(endtime - starttime); public class CompetitionHandler { private Competition competition; result = competition.getraces()[i].getresults()[j]; starttime = result.getstarttime().getseconds(); endtime = result.getendtime().getseconds(); result.settotaltime(endtime - starttime); EDAF25 (F3) VT 2015 13 / 50 Competition Lokalitetsprinicpen! EDAF25 (F3) VT 2015 14 / 50 Race Lokalitetsprinicpen! public class Competition { private ArrayList<Race> races; public void computetotal() { for(race race: races ) { race.computetotal(); Delegerar arbetet till den klass som vet allt om Race: public class Race { private ArrayList<Result> results; public void computetotal() { for(result result: results) { result.computetotal(); Delegerar arbetet till den klass som vet allt om Result: EDAF25 (F3) VT 2015 15 / 50 EDAF25 (F3) VT 2015 16 / 50
SRP Enkelt ansvar Time har bara ett ansvarsområde SRP Enkelt ansvar Single Responsibility Principle A class should have only one reason to change. (Martin) En klass med flera ansvarsområden ger bräcklighet. En klass utan ansvar är onödig. public class Time implements Comparable<Time> { private int sec; public Time difference(time other) public int compareto(time other) public String tostring() public Time(String time) EDAF25 (F3) VT 2015 17 / 50 Result har flera SRP Enkelt ansvar EDAF25 (F3) VT 2015 18 / 50 Delegera ansvaren! SRP Enkelt ansvar public class Result { private String firstname, secondname; private String idnumber; private int starttime, endtime; public String fullname(){ private boolean checkidnumber(){ public int totaltime() { return endtime - starttime; public class Result { private Name name; private IdNumber idnumber; private Time start, end; public String fullname() { return name.tostring(); public Time total() { return end.difference(start); EDAF25 (F3) VT 2015 19 / 50 EDAF25 (F3) VT 2015 20 / 50
GenerateCode har massor av ansvar SRP Enkelt ansvar Vilka ansvarsområden? SRP Enkelt ansvar public static void generatecode(instruction c) { switch (c.opcode) { case 0: //MOV if (!(c.arg1 instanceof Current c.arg1 instanceof Next) &&!(c.arg2 instanceof Current c.arg2 instanceof Next { out.writebytes( mov + code.convert(c.arg1) +, + code.convert(c.arg2) + \n ); else if ((c.arg1 instanceof IntConst c.arg1 instanceof BoolConst) && c.arg2 instanceof Current) { out.writebytes( mov + code.convert(c.arg1)+, + code.savetoreg(c.arg1) + \n ); out.writebytes( set + code.convert(c.arg2,staticlevel 1) +, + code.savetoreg(c.arg2) + \n ); out.writebytes( st + code.savetoreg(c.arg1) +, + [ + code.savetoreg(c.arg2) + ]\n ); else if((c.arg1 instanceof Temp) && c.arg2 instanceof Current) { out.writebytes( set + code.convert(c.arg2,staticlevel 1) +, + code.savetoreg(c.arg2) + \n ); out.writebytes( st + code.savetoreg(c.arg1) +, + [ + code.savetoreg(c.arg2) + ]\n ); else if(c.arg1 instanceof Current && c.arg2 instanceof Temp) { out.writebytes( set + code.convert(c.arg2) +, + code.savetoreg(c.arg2) + \n ); out.writebytes( ld + [ + code.savetoreg(c.arg2) + ] +, + code.savetoreg(c.arg1) + \n ); else if(c.arg1 instanceof Current && c.arg2 instanceof Current) { if(!(c.arg1.tostring().equals(c.arg2.tostring()))) { out.writebytes( set + code.convert(c.arg1,staticlevel 1) +, + code.savetoreg(c.arg2) + \n ); Kodgenerering för: MOV-instruktionen OR-instruktionen Current-operander Temp-operander EDAF25 (F3) VT 2015 21 / 50 Aktivitet Gör en bättre design! EDAF25 (F3) VT 2015 22 / 50 Open/Closed Principle Classes should be open for extension and closed for modification. (Meyer) Det skall vara möjligt att lägga till ny funktionalitet utan att modifiera existerande kod. EDAF25 (F3) VT 2015 23 / 50 EDAF25 (F3) VT 2015 24 / 50
Expr-klasserna tillämpar Open/Closed-principen Aktivitet Man kan lägga till nya uttryck utan att ändra något i de gamla. Man kan lägga till Sub, Mul och Div. Aktivitet: Lägg till en Abs-operation som ger absoluta värdet av ett uttryck och implementera value()! public class Abs implements Expr { private Expr expr; public int value{ return Math.abs(expr.value()); EDAF25 (F3) VT 2015 25 / 50 Dålig design: Circle, Square EDAF25 (F3) VT 2015 26 / 50 Dålig design: Figure public class Circle { int radius; int x, y; public Circle(int radius, int x, int y) { this.radius = radius; this.x = x; this.y = y; Square är analog. public class Figure extends ArrayList { public Figure() { add(new Square(4, 1, 1)); add(new Circle(4, 2, 2)); public void draw() { for (Object object: this) { if (object instanceof Square) { drawsquare((square) object); else { drawcircle((circle) object); EDAF25 (F3) VT 2015 27 / 50 EDAF25 (F3) VT 2015 28 / 50
Dålig design: Figure Dålig design: Figure public class Figure { private static void drawcircle(circle circle) { // TODO Implement method private static void drawsquare(square square) { // TODO Implement method EDAF25 (F3) VT 2015 29 / 50 Circle & Shape & Figure EDAF25 (F3) VT 2015 30 / 50 Circle & Shape & Figure public class Circle implements Shape { private int radius; private int x, y; public void paint(graphics graphics) { // TODO Auto-generated method stub public interface Shape { public void paint(grahpics graphics); public class Figure extends ArrayList<Shape> { public void paint(graphics graphics) { for (Shape shape : list) { shape.paint(graphics); EDAF25 (F3) VT 2015 31 / 50 EDAF25 (F3) VT 2015 32 / 50
DIP Bero på abstraktion Figure: Dålig design DIP Bero på abstraktion Dependency Inversion Principle High level classes should not depend on low level classes; both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions (Martin) UML-pilar skall gå mot gränssnitt och abstrakta klasser. EDAF25 (F3) VT 2015 33 / 50 Bättre! DIP Bero på abstraktion EDAF25 (F3) VT 2015 34 / 50 UML klassdiagram Övning Rita ett klassdiagram som visar alla klasser, gränssnitt, associationer, metoder, konstruerare och attribut som förekommer i klassen StarButton nedan. public class StartButton extends Button implements ActionListener { private Train train; public StartButton(Train train) { super("start"); this.train = train; addactionlistener(this); public void actionperformed(actionevent event) { train.start(); EDAF25 (F3) VT 2015 35 / 50 EDAF25 (F3) VT 2015 36 / 50
Objektorienterad modellering och design (EDAF25) Designprinciper Riktlinjer som hjälper oss att undvika en dålig design En generell återanvändbar lösning på ett vanligt förekommande problem i en given kontext Vi börjar med att titta på två mönster och Composite «interface» + execute() EDAF25 (F3) VT 2015 37 / 50 EDAF25 (F3) VT 2015 38 / 50 Användning: commandlist:arraylist<> List<> commandlist = new ArrayList<>(); commandlist.add(new PenDown()); commandlist.add(new Move(1, 0)); commandlist.add(new Move(0, 1)); commandlist.add(new Move(-1, 0)); commandlist.add(new Move(0, -1)); commandlist.add(new PenUp()); :PenDown :Move x= 1 y=0 :Move x=0 y=1 for ( command : commandlist) { command.execute(); :Move x=-1 y=0 :Move x=0 y=-1 :PenUp EDAF25 (F3) VT 2015 39 / 50 EDAF25 (F3) VT 2015 40 / 50
«interface» Transaction + validate() + execute() Med undo: public interface { public void execute(); public void undo(); AddStudent EDAF25 (F3) VT 2015 41 / 50 EDAF25 (F3) VT 2015 42 / 50 Composite Fördelar: Man delegerar arbetet till (små) klasser med enkelt ansvar. Separation i tiden mellan konstruktion och exekvering av kommandon Separation i rummet mellan konstruktion och exekvering av kommandon Historielista Undo Leaf «interface» Composite + method(context) * Node EDAF25 (F3) VT 2015 43 / 50 EDAF25 (F3) VT 2015 44 / 50
Exempel Exempel Ni kommer ihåg Nu med Composite EDAF25 (F3) VT 2015 45 / 50 Composite EDAF25 (F3) VT 2015 46 / 50 Composite public class Macro implements { private List<> commandlist = new ArrayList<>(); public void add( command) { commandlist.add(command); public void execute() { for ( command : commandlist) { command.execute(); public class Macro extends ArrayList<> implements { public void execute() { for ( command : this) { command.execute(); Enklare, men med sämre integritet EDAF25 (F3) VT 2015 47 / 50 EDAF25 (F3) VT 2015 48 / 50
Composite Composite Expr har Composite-struktur Användning: Macro macro = new Macro(); macro.add(new PenDown()); macro.add(new Move(2, 0)); macro.add(new Move(0, 2)); macro.add(new Move(-2, 0)); macro.add(new Move(0, -2)); macro.add(new PenUp()); «interface» Expr + value(): int * macro.execute(); new Move(1, 1).execute(); macro.execute(); Num - value: int Add EDAF25 (F3) VT 2015 49 / 50 EDAF25 (F3) VT 2015 50 / 50