Software Engineering I (02161) · Software Engineering I (02161) S.O.L.I.D. principles Assoc. Prof....
Transcript of Software Engineering I (02161) · Software Engineering I (02161) S.O.L.I.D. principles Assoc. Prof....
Software Engineering I (02161)S.O.L.I.D. principles
Assoc. Prof. Hubert Baumeister
DTU ComputeTechnical University of Denmark
Spring 2020
S.O.L.I.D. Principles
I Single responsibility principle
I Open/closed principleI Liskov substitution principleI Interface segregation principleI Dependency inversion principle
S.O.L.I.D. Principles
I Single responsibility principleI Open/closed principle
I Liskov substitution principleI Interface segregation principleI Dependency inversion principle
S.O.L.I.D. Principles
I Single responsibility principleI Open/closed principleI Liskov substitution principle
I Interface segregation principleI Dependency inversion principle
S.O.L.I.D. Principles
I Single responsibility principleI Open/closed principleI Liskov substitution principleI Interface segregation principle
I Dependency inversion principle
S.O.L.I.D. Principles
I Single responsibility principleI Open/closed principleI Liskov substitution principleI Interface segregation principleI Dependency inversion principle
Single responsibility principleI ”A class should have only a single responsibility”
Rectangle
origin: Pointextent: Point
area: doubledraw(g: Graphics)
ComputationalGeometry
Application
GraphicalApplication
GUI
Single responsibility: Possible solutionI ”A class should have only a single responsibility”
GeometricRectangle
origin: Pointextent: Point
area: double
Rectangle
draw(g: Graphics)
ComputationalGeometry
Application
GraphicalApplication
GUI
I Responsibility→ axis of change (cohesion!)
Open/Closed Principle
I Bertrand Meyer (88): ”Modules should be open for extension, but closed formodification.”
for (Shape s : shapes) { switch (s.type) { case CIRCLE: drawCircle(s); case SQUARE: drawSquare(s); }}
Shape
point: Pointvalue: double
«enumeration»ShapeType
CIRCLESQUARE
Picture
drawAllShapesdrawCircledrawSquare *
type1
Open/Closed Principle
I Bertrand Meyer (88): ”Modules should be open for extension, but closed formodification.”
for (Shape s : shapes) { switch (s.type) { case CIRCLE: drawCircle(s); case SQUARE: drawSquare(s); }}
Shape
point: Pointvalue: double
«enumeration»ShapeType
CIRCLESQUARE
Picture
drawAllShapesdrawCircledrawSquare *
type1
Note..for (Shape s : shapes) { s.draw}
Shape
draw
Square
topLeft: Pointheight: double
draw
Circle
center: Pointradius: double
draw
DrawingApplication
drawAllShapes*
Liskov Substition Principle (LSP)
Subtype property S is a subtype of T :”Let φ(x) be a property provable about objects x of type T . Then φ(y) should betrue for objects y of type S where S is a subtype of T .”Liskov, B. H.; Wing, J. M. (November 1994). A behavioral notion of subtyping.
I Property φ(x): object x of T understands method m
→ then object of S has to understand mI In most OO languages, like Java, by construction:
class S extends T {...}
Liskov Substition Principle (LSP)
Subtype property S is a subtype of T :”Let φ(x) be a property provable about objects x of type T . Then φ(y) should betrue for objects y of type S where S is a subtype of T .”Liskov, B. H.; Wing, J. M. (November 1994). A behavioral notion of subtyping.
I Property φ(x): object x of T understands method m→ then object of S has to understand m
I In most OO languages, like Java, by construction:class S extends T {...}
Liskov Substition Principle (LSP)
Subtype property S is a subtype of T :”Let φ(x) be a property provable about objects x of type T . Then φ(y) should betrue for objects y of type S where S is a subtype of T .”Liskov, B. H.; Wing, J. M. (November 1994). A behavioral notion of subtyping.
I Property φ(x): object x of T understands method m→ then object of S has to understand mI In most OO languages, like Java, by construction:
class S extends T {...}
GetFine ExampleBehaviour conformanceI However: ”has the same methods” is not enough
Book
..
getFine: int
CD
getFine: int
I Book getFine returns 100
I CD getFine returns 200
I Property Φ(b : Book) iff b.getFine() = 100 holds forbooks:
I Φ(new Book()) = true
I LSP: should hold for subclass
I Subclass Φ(new CD()) = false
GetFine ExampleBehaviour conformanceI However: ”has the same methods” is not enough
Book
..
getFine: int
CD
getFine: int
I Book getFine returns 100
I CD getFine returns 200
I Property Φ(b : Book) iff b.getFine() = 100 holds forbooks:
I Φ(new Book()) = true
I LSP: should hold for subclass
I Subclass Φ(new CD()) = false
GetFine ExampleBehaviour conformanceI However: ”has the same methods” is not enough
Book
..
getFine: int
CD
getFine: int
I Book getFine returns 100
I CD getFine returns 200
I Property Φ(b : Book) iff b.getFine() = 100 holds forbooks:
I Φ(new Book()) = true
I LSP: should hold for subclass
I Subclass Φ(new CD()) = false
GetFine Example solution
Book
getFine: int
Medium
..
getFine: int
CD
getFine: int
I Medium and getFine are abstractI Expectation/contract for getFine()
I Φ(m : Medium) iff m.getFine() ≥ 0→ Design by contract
I Φ(newBook()) = trueI Φ(newCD()) = true.
Conclusion: When creating a subclass, make sure that it satisfies allexpectations/contracts from the superclass
GetFine Example solution
Book
getFine: int
Medium
..
getFine: int
CD
getFine: int
I Medium and getFine are abstractI Expectation/contract for getFine()
I Φ(m : Medium) iff m.getFine() ≥ 0→ Design by contract
I Φ(newBook()) = trueI Φ(newCD()) = true.
Conclusion: When creating a subclass, make sure that it satisfies allexpectations/contracts from the superclass
GetFine Example solution
Book
getFine: int
Medium
..
getFine: int
CD
getFine: int
I Medium and getFine are abstractI Expectation/contract for getFine()
I Φ(m : Medium) iff m.getFine() ≥ 0→ Design by contract
I Φ(newBook()) = trueI Φ(newCD()) = true.
Conclusion: When creating a subclass, make sure that it satisfies allexpectations/contracts from the superclass
Interface Segregation Principle
Clients 1/2 depend on functionality theydon’t need
Separate out needed functionality ininterfaces
Interface Segregation Principle
Clients 1/2 depend on functionality theydon’t need Separate out needed functionality in
interfaces
Dependency-Inversion Principle (DIP)
DetailClass
AbstractClass
A. ”High-level modules should not depend on low-level modules. Both shoulddepend on abstractions.”
Robert C. Martin (2007) Agile Principles, Patterns, and Practices in C#
Furnace Example
const byte TERMOMETER = 0x86; const byte FURNACE = 0x87;const byte ENGAGE = 1;const byte DISENGAGE = 0;
void Regulate(double minTemp, double maxTemp) {for(;;) {
while (in(THERMOMETER) > minTemp)wait(1);
out(FURNACE,ENGAGE);while (in(THERMOMETER) < maxTemp)wait(1);
out(FURNACE,DISENGAGE);}
}
Dependency-Inversion Principle (DIP)
DetailClass
AbstractClass
A. ”High-level modules should not depend on low-level modules. Both shoulddepend on abstractions.”
Robert C. Martin (2007) Agile Principles, Patterns, and Practices in C#
«interface»Abstraction
DetailClass
AbstractClass
Furnace Example Solution
void Regulate(Thermometer t, Heater h,double minTemp,double maxTemp)
{for(;;)
{while (t.Read() > minTemp)wait(1);
h.Engage();while (t.Read() < maxTemp)wait(1);
h.Disengage();}
}
Robert C. Martin (2007) Agile Principles, Patterns, and Practices in C#