object-oriented design principles - ntutyccheng/oop2007f/ood principles-v0.4.pdf · object-oriented...

79
1 Object-Oriented Design Principles Chien-Tsun Chen ( 陳建村 ) Department of Computer Science and Information Engineering National Taipei University of Technology, Taipei 106, Taiwan [email protected] Dec. 04 2007

Upload: buithu

Post on 28-Jul-2018

224 views

Category:

Documents


0 download

TRANSCRIPT

1

Object-Oriented Design Principles

Chien-Tsun Chen (陳建村)Department of Computer Science and Information EngineeringNational Taipei University of Technology, Taipei 106, Taiwan

[email protected]. 04 2007

2

OOD principles roadmap: What distinguishes good and bad OO design?

Class

Inheritance

polymorphism

Program to an interface, not an implementation

Favor object composition over class inheritance

Separation of concern

Single Responsibility

Open-Closed

Liskov Substitution

Dependency-Inversion

Interface-Segregation

basic advanced

4

Outline

SRP—The Single Responsibility PrincipleOCP—The Open-Closed PrincipleLSP—The Liskov Substitution PrincipleDIP—The Dependency-Inversion PrincipleISP—The Interface-Segregation Principle

5

Example first: Designing a Student class

What responsibilities a Student class should have?

R1: Representing data (name, age, etc)R2: PersistenceR3: Reporting

6

You may end up with the following Student class

R1: Data model

R2: Persistence

R3: Reporting

Does anything wrong with the design?

7

What are the problems of the previous design?

Responsibility couplingViolating separation of concerns

There are many reasons to change the class

+ getName()

+ setName()...

+ save()+ load()

+ toHTML()+ toPDF()+ toWord()...

How to avoid responsibility coupling?

Applying Single- Responsibility Principle (SRP)

9

What is Single-Responsibility Principle (SRP)?

Definition: A class should have only one reason to change.

SRP avoids responsibility coupling

10

Applying SRP to the Student class

Data model

+ toHTML()

+ toPDF()

+ toWord()...

Persistence Reporting

11

But my OO text book tells me to simulate real world “things” as classes…

A Student class have to be stored.

It should be reported to users.

So, why these responsibilities cannot be assigned to the Student class?

12

Things in large

The original design is fine, ifThe application has few classes

Think about this:How to persist several different types of classes?

Student, Teacher, School, Test Result, etc.

13

Persistence layer

+CalculatePay()+Store()

Employee

Persistence subsystem

+CalculatePay()

Employee

Broker

Persistence subsystem

coupled persistence

separated persistence

14

Grain size of a class

A class should represents only one abstraction (or a responsibility)

Responsibility coupling harms:ReusabilityModifiabilityTestabilityUnderstandabilityetc

15

Another example that violates Single- Responsibility Principle

More than one responsibility

16

Problems of violation SRP in this example

The computational geometry application must include the GUI.If changes to the GraphicalApplicationcause the Rectangle to change, we may need to rebuild, retest, and redeply the ComputationalGeometryApplication.

17

Separating responsibilities changes dependencies as well

+draw()

before

after

18

Responsibility: a reason for change

Thinking about responsibilities in groups

19

Separating Modem interface

20

An example from OOMD, p. 35

21

Case Study 1: A GUI Test AP.

1

2

22

Summary of the Single-Responsibility Principle

SRP: A class should have only one reason to change.

Conjoining responsibilities is something that we do naturally. Finding and separating those responsibilities from one another is much of what software design is really about.

separation of concern

23

Outline

SRP—The Single Responsibility PrincipleOCP—Then Open-Closed PrincipleLSP—The Liskov Substitution PrincipleDIP—The Dependency-Inversion PrincipleISP—The Interface-Segregation Principle

24

You are designing a drawing application

Data structure of the application

25

How to draw all shapes?

26

What are the problems of the design?

27

A single change to a program results in a cascade of changes to dependent modules

The design depends on a switch-case statement

28

Things to do when you want to add a new type of shape, e.g., Line

Create a new struct/class of LineModify the drawAllshapes methodswitch (s->itsType) {case square: …case circle: …case line: …

}

29

An OO solution

The OO design satisfies Open-Closed Principle

31

What is Open-Closed Principle (OCP)?

Definition: Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

Extend systems by adding new code (the open part), not by changing old code that already works (the closed part).

32

The open and the closed parts

Closed for modification

Open for extension

Closed for modification1

2

3

33

Two primary attributes of the Open- Closed Principle

They are “Open for Extension”:The behavior of the module can be extended. We can make the module behave in new and different ways as the requirements of the application change, or to meet the needs of new applications.

They are “Closed for Modification”:The source code of such a module is inviolate. No one is allowed to make source code changes to it.

34

Abstraction is the Key to OCP (1/2)

Client Server

Client AbstractServer

Server

Closed

Open

35

Abstraction is the Key to OCP (2/2)

Template Method Pattern: Base class is open and closed

Closed

Open

36

Question : What is abstraction?

Thinking about what you can do rather than who you are.

What: ListWho: ArrayList, LinkedList

37

How to achieve the open-closed principle?

Putting the hooks in:Finding hot spots (simulating change)

Using abstraction to gain explicit closureProgramming to interface

Using a data-driven (table-driven) approach to achieve closure

Using Configuration, Register, or Repository

38

Summary of the Open-Closed Principle

OCP: Software entities should be open for extension, but closed for modification.

The OCP is the foundation for building maintainable and reusable systems.

The primary mechanisms behind the OCP are abstraction and polymorphism.

39

Case Study 2

If FTP should be supported, what will you do ?

If you want to upgrade RMH from version A to B…

Bad class name

How to test TransmissionWizard?

40

Outline

SRP—The Single Responsibility PrincipleOCP—The Open-Closed PrincipleLSP—The Liskov Substitution PrincipleDIP—The Dependency-Inversion PrincipleISP—The Interface-Segregation Principle

41

What is the Liskov Substitution (LSP)?

Definition 1: Subtypes must be substitutable for their base types.

Shape myShape;…

myShape = new myCirlce();myShape.draw();…

myShape = new Square();myShape.draw();

+draw()

Shape

+draw()

Circle

+draw()

Square

42

What is the Liskov Substitution (LSP)?

Definition 2: Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

Shape myShape;…

myShape = new myCirlce();myShape.draw();…

myShape = new Square();myShape.draw();

+draw()

Shape

+draw()

Circle

+draw()

Square

43

A drawing application violates LSP

+getTypeShape

+Draw+getCenter+getRadius

Circle

+Draw+getTopLeft

Square

44

Modifying the Shape class to satisfy LSP

+Draw()+getType

Shape

+Draw+getCenter+getRadius

Circle

+Draw+getTopLeft

Square

void DrawShape (const Shape& s) {s.Draw();

}

45

A more subtle violation of LSP (1/2)

Rectangle

Square

46

A more subtle violation of LSP (2/2)

Square s;g (s);

You will get an assertion violation exception:“Expect 20 but 16.”

Why?

47

What Went Wrong?

The behavior of a Square object is not consistent with the behavior of a Rectangle object. Behaviorally, a Square is not a Rectangle! And it is behavior that software is really all about.The LSP makes clear that in OOD the IS-A relationship pertains to behavior.

48

Applying Design by Contract to conform the LSP

Assertion:Precondition.Postcondition.Class invariant.

The rule for the preconditions and postconditions for derivatives:

when redefining a routine [in a subclass], you may only replace its precondition by a weaker one, and its postcondition by a stronger one.

49

Review the example: the contract is broken in the Square class

postcondition of Rectangle::SetWidth(double w)

The postcondition of Square::SetWidth(double w) is weaker than the postcondition of Rectangle::SetWidth(double w) above Rectangle

Square

assert ((itsWidth == w) && (itsHeight == w))

assert ((itsWidth == w) && (itsHeight == old.itsHeight))

50

Summary of the Liskov Substitution Principle

LSP: Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it

The LSP (A.K.A. Subcontracting) is an important feature of all programs that conform to the Open-Closed principle.

51

Case Study 3

52

+Article() : int+show()+setSelect(in location)+set_text()+get_text()

Article

+show()+setSelect(in position : int)+Sentence()+next_positionX()+next_positionY()

Sentence

+show()+set_word(in letter : Letter, in position : int)+Word()

Word

+Letter()

Letter

+setlocation(in location)+getlocation()+show()+changeLetter(in letter : Letter, in position : int)+setSelect()+Text()+get_selected()+get_textarea()

Text

1

*

Case Study 4

53

Design Review 5

54

Outline

SRP—The Single Responsibility PrincipleOCP—The Open-Closed PrincipleLSP—The Liskov Substitution PrincipleDIP—The Dependency-Inversion PrincipleISP—The Interface-Segregation Principle

55

What is the Dependency-Inversion Principle?

Definition a: high-level modules should not depend on low-level modules. Both should depend on abstractions.Definition b: abstractions should not depend on details. Details should depend on abstractions.

This principle is at the heart of framework design

56

A naive layering structure violates the Dependency-Inversion Principle

Policy layer is sensitive to changes all the way down in the Utility layer. Dependency is transitive.

57

A more appropriate model: each of the upper- level layers declares an abstract interface for the services that it needs

the dependency has been inverted

The lower-level layers are realized form the abstract interface

The lower-level layers are realized form the abstract interface

PolicyLayer can be reused in any context that defines lower-level modules that conform to the PolicyServiceInterface

58

Not only the dependency, but also the ownership are inverted

We often think of utility libraries as owning their own interfaces.But when the DIP is applied, the clients tend to own the abstract interfaces and that their servers derive from them.

59

Dependency inversion can be applied wherever on class sends a message to another

Simple model of a Button and a Lamp

Dependency inversion applied to the Lamp

More testable

60

Summary of the Dependency- Inversion Principle

DIP: High- and low-level modules should depend on abstractions, not depend on each other.It is the inversion of dependencies that is the hallmark of good OO design. If a system’s dependencies are inverted, it has an OO design. Otherwise, it has a procedural design.

61

Outline

SRP—The Single Responsibility PrincipleOCP—The Open-Closed PrincipleLSP—The Liskov Substitution PrincipleDIP—The Dependency-Inversion PrincipleISP—The Interface-Segregation Principle

62

A security system example

We want to implement a TimedDoor class

63

A possible design of the TimedDoor class

class abstract Door {public void lock();public void unLock();public boolean isDoorOpen();

}

class Timer {public void register(

int timeout,TimerClient client);

}

interface TimerClient {void timeout ();

}

Door has been polluted with a method that it does not require

We want to implement a TimedDoor class

The design violates Interface- Segregation Principle (ISP)

64

What is the Interface-Segregation Principle?

Definition: clients should not be forced to depend on methods that they do not use

This principle deals with the disadvantages of fat interfaces

65

Two direction of forces that cause changes in software

How changes to interfaces will affect their users

Client may also forces a change to the interface

66

Separate clients mean separate interfaces

If users of Timer require to register more than one time-out request, a false alarm bug may occur

Door interface &TimerClient interface

Door &TimerClient

TimerClientinterface

Door Client

The change will affect all the users of TimerClient. That is ok. But why should a bug in TimerClient have any affect on clients of Door that do not require timing?

67

Separation of interfaces through delegation and multiple inheritance

Door Timer adapter

Multiply inherited Timed Door

68

Summary of the Interface- Segregation Principle

ISP: Clients should not be forced to depend on methods that they do not use.

The ISP breaks the dependence of the clients on methods that they do not invoke, and it allows the clients to be independent of each other.

69

Using the following OO design principles well will greatly improve your OO capability

Question?

70

71

72

Narrow inheritance interface principle

Behavior that is spread over several methods in a class should be based on a minimal set of methods which have to be overriddenOtherwise clients deriving subclasses would have to overridden many methods to adapt that behaviorOverriding the smaller hook methods has to be

sufficient in order to adapt the more complex template methods

73

74

Using abstraction to gain explicit closure (1/2)

public void drawAll (Shape [] list) {

for (int i = 0; I < list.length; i++) { list[i].draw();

}}

+draw()

Shape

+draw()

Circle

+draw()

Square

drawAll conforms the Open-Closed Principle since adding new subclass of Shape have not to change its implementation

75

Using abstraction to gain explicit closure (2/2)

public void print (ArrayList list) {….

}

public void print (List list) {….

}

public List get () {

List list = new ArrayList();….

return list;}

public ArrayList get () {

ArrayList list = new ArrayList();….

return list;}

prefer doing soavoid doing so

76

77

Registering more than one time-out request may cause the Door alarms falsely

Consider the TimedDoor. When it detects that the Door has been opened, it sends the Register message to the Timer, requesting a time-out. However, before the time-out expires, the door closes, remains closed for a while, and then opens again. This causes us to register a new time-out request before the old one has expired. Finally, the first time-out request expires and the TimeOut function of the TimedDoor is invoked. The Door alarms falsely.

78

Change of requirement: Some users of Timer will register more than one time-out request

class Timer {public void register(

int timeout,TimerClient client);

}

interface TimerClient {void timeout();

}

Timer with ID

class Timer {public void register(

int timeout,int timeoutID,TimerClient client);

}

interface TimerClient {void timeout(int timeoutID);

}

The original Timer

79

Separation of interfaces through Extension Object (Extension Interface)

public class TimedDoor {

Object getAdapter (Class adapter){return AdapterManager.getAdapter(

this, adapter);

}}