Objektorienterad modellering och design (EDAF25) Föreläsning 3 UML Objektdiagram Agenda UML objekt och sekvensdiagram Design smells Designprinciper (DRY, SRP, OCP, DIP) (, ) Att göra denna och nästa vecka: Läs Martin 7-9,11,13 och 23 Ö1 och L2 redovisas imorgon! Frivillig laboration Eclipse/UML Handledning erbjuds på fredag! Ö2 redovisas nästa fredag! EDAF25 (F3) VT 2017 1 / 52 UML Objektdiagram EDAF25 (F3) VT 2017 2 / 52 UML Sekvensdiagram (1+2) + 3 EDAF25 (F3) VT 2017 3 / 52 EDAF25 (F3) VT 2017 4 / 52
UML Sekvensdiagram Aktivitet UML Sekvensdiagram (1+2) + 3 Visa beräkning av (1 + 2) + 3 i ett sekvensdiagram. EDAF25 (F3) VT 2017 5 / 52 UML Sekvensdiagram Martin EDAF25 (F3) VT 2017 6 / 52 Principles (11st - lista längst bak i insidan av pärmen iboken +1), Patterns (11st - av 23 i listan innan Section 1 i boken), and Practices (andra kurser) EDAF25 (F3) VT 2017 7 / 52 EDAF25 (F3) VT 2017 8 / 52
Principles Patterns SRP - The Single Responsibility Principle OCP - The Open-Closed Principle DIP - The Dependency Inversion Principle DRY - Don t Repeat Yourself Principle ISP - The Interface Segregation Principle LSP - The Liskov Substitution Principle REP - The Release-Reuse Ecuivalency Principle CCP - The Common Closure Principle CRP - The Common Reuse Principle ADP - The Acyclic Dependencies Principle SDP - The Stable Dependencies Principle SAP - The Stable Abstraction Principle Visitor Template Strategy Singleton Null Object Facade Decorator Observer Factory (MVC - Model View Control) EDAF25 (F3) VT 2017 9 / 52 Design smells EDAF25 (F3) VT 2017 10 / 52 Agil design 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" Agil praxis -> Identifikation av ett problem Designprinciper -> Diagnosticering av problemen -> Lösning av problemet Exempel i Martin s.90-94 "Kopieringsprogrammet" EDAF25 (F3) VT 2017 11 / 52 EDAF25 (F3) VT 2017 12 / 52
Mått på designkvalitet Exempel på dålig design Koppling (Coupling) - Graden av beroenden till andra moduler i systemet Sammanhang(Cohesion) - Graden av samhörighet mellan medlemmarna i samma modul 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); EDAF25 (F3) VT 2017 13 / 52 Fortfarande dålig EDAF25 (F3) VT 2017 14 / 52 Competition Lokalitetsprinicpen! public class CompetitionHandler { private Competition competition; result = competition.getraces()[i].getresults()[j]; starttime = result.getstarttime().getseconds(); endtime = result.getendtime().getseconds(); result.settotaltime(endtime - starttime); 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: EDAF25 (F3) VT 2017 15 / 52 EDAF25 (F3) VT 2017 16 / 52
Race Lokalitetsprinicpen! SRP Enkelt ansvar 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: 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. EDAF25 (F3) VT 2017 17 / 52 Time har bara ett ansvarsområde SRP Enkelt ansvar EDAF25 (F3) VT 2017 18 / 52 Result har flera SRP Enkelt ansvar 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) 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; EDAF25 (F3) VT 2017 19 / 52 EDAF25 (F3) VT 2017 20 / 52
Delegera ansvaren! SRP Enkelt ansvar GenerateCode har massor av ansvar SRP Enkelt ansvar 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); 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 ); EDAF25 (F3) VT 2017 21 / 52 Vilka ansvarsområden? SRP Enkelt ansvar EDAF25 (F3) VT 2017 22 / 52 Aktivitet Gör en bättre design! Kodgenerering för: MOV-instruktionen OR-instruktionen Current-operander Temp-operander EDAF25 (F3) VT 2017 23 / 52 EDAF25 (F3) VT 2017 24 / 52
DRY Undvik upprepning Don t Repeat Yourself Principle Every piece of knowledge must have a single, unambiguous, authoritative representation within a system (Hunt and Thomas) 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 2017 25 / 52 Expr-klasserna tillämpar Open/Closed-principen EDAF25 (F3) VT 2017 26 / 52 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 2017 27 / 52 EDAF25 (F3) VT 2017 28 / 52
Dålig design: Circle, Square 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 2017 29 / 52 Dålig design: Figure EDAF25 (F3) VT 2017 30 / 52 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 2017 31 / 52 EDAF25 (F3) VT 2017 32 / 52
Circle & Shape & Figure 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 2017 33 / 52 DIP Bero på abstraktion EDAF25 (F3) VT 2017 34 / 52 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 2017 35 / 52 EDAF25 (F3) VT 2017 36 / 52
Bättre! DIP Bero på abstraktion 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 EDAF25 (F3) VT 2017 37 / 52 EDAF25 (F3) VT 2017 38 / 52 Användning: «interface» + execute() 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()); for ( command : commandlist) { command.execute(); EDAF25 (F3) VT 2017 39 / 52 EDAF25 (F3) VT 2017 40 / 52
commandlist:arraylist<> «interface» Transaction :PenDown :Move :Move + validate() + execute() x= 1 y=0 x=0 y=1 :Move :Move :PenUp x=-1 y=0 x=0 y=-1 AddStudent EDAF25 (F3) VT 2017 41 / 52 EDAF25 (F3) VT 2017 42 / 52 Med undo: public interface { public void execute(); public void undo(); Invoker Client «interface» Concrete Receiver EDAF25 (F3) VT 2017 43 / 52 EDAF25 (F3) VT 2017 44 / 52
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» + method(context) * Node EDAF25 (F3) VT 2017 45 / 52 Exempel EDAF25 (F3) VT 2017 46 / 52 Exempel Ni kommer ihåg Nu med EDAF25 (F3) VT 2017 47 / 52 EDAF25 (F3) VT 2017 48 / 52
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 2017 49 / 52 EDAF25 (F3) VT 2017 50 / 52 Expr har -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 2017 51 / 52 EDAF25 (F3) VT 2017 52 / 52