Download presentation
Presentation is loading. Please wait.
Published bySilvester Wilkins Modified over 9 years ago
1
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 1 Object-Oriented Analysis and Design - CDT309 Period 4, Spring 2008 Open-closed principle
2
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 2 Object connectivity Client classes use services from supplier classes: A module (class) is open when it’s available for extension (add, enlarge). A module is closed if it’s not subject to further change (it has a fixed number of functions). Client Supplier >
3
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 3 Advantages Closed module: can be used as a stable component in the system, avoiding changes that potentially affect the whole design Open module: make it possible to extend and modify the system in the awake of new capabilities and functionalities, keeping maintenace costs down
4
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 4 Open-Closed Principle We should try to produce modules that are simultaneously open and closed. This looks like a contradiction!
5
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 5 General solution Distinguish between interface and implementation. –Implementation can be modified without affecting clients. –How can we do this? What’s the interface?
6
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 6 General solution The interface is the public definitions public class Supplier { private int attribute; public void operation() { // implementation of operation } } Operation visible to the client
7
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 7 General solution - advantages We can change the implementation of the operation in the supplier without the need to change the client We can add new operations and attributes also without the need to change any the client Is this a good solution?
8
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 8 General solution - limitations In C++, modifications in the header (as if you want to add a private attribute in the Supplier) requires clients modules to be recompilated, even if the changes are invisible to them. –The open-closed principle should be language- independent. Different clients of a module can use different subsets of the visible interface. –It is difficult to know exactly what changes to a module will affect a given client. Can we have a better solution?
9
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 9 Let’s use abstract classes New subclasses can be added, extending (or specializing) the AbstractSupplier or providing alternative implementation of the interface.
10
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 10 Java’s code public abstract class AbstractSupplier { public abstract void operation(); } public class ConcreteSupplier extends AbstractSupplier { private int attribute; public void operation() { // implementation of operation } }
11
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 11 Abstract classes Dependencies: The use of abstract classes is fundamental for working with design patterns.
12
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 12 Abstract classes What happens If we need to modify the interface of the AbstractSupplier due to changes on the needs of the client (like add a new operation)? We need more principles…
13
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 13 Principle: No Concrete SuperClass All Superclasses should be abstract. Only leaf classes should be concrete. Why? Let’s see an example… Changes ahead: the bank wants to add a savings account. How would you do that? A class to provide accounts in a bank.
14
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 14 Easy solution: The subclass inherits the shared functionalities Concrete superclass
15
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 15 Doing changes Now the bank decides to allow accounts become overdraw, but not on SavingsAccount’s. How to do that?
16
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 16 One possibility public class CurrentAccount {... void withdraw (double amt) { if (this.instanteof SavingsAccount) { // check if becoming overdraw } balance -= amt; }... } What are possible problems with this solution? Chech the type of the account
17
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 17 Problems with extension Public class CurrentAccount { void withdraw (double amt) { if (this.instanteof SavingsAccount) { // check if becoming overdraw } balance -= amt; } } If there is a new subclass, changes on this code will be necessary: the module is not closed. The superclass is aware of the existence of subclasses!
18
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 18 Problems with extension void cashCheque (currentAccount a) { if (this.instanceof SavingsAccount) { return; } // cash cheque } Adding new functionalities. For example: add cheques capabilities, but not on SavingsAccounts. Could be like: What is causing the problems?
19
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 19 The cause of the problem void cashCheque (currentAccount a) { if (this.instanceof SavingsAccount) { return; } // cash cheque } Role 1: as a superclass, this interface is implemented by all accounts objects and subclasses Role 2: it is also providing a default implementation This superclass has two roles
20
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 20 General solution All superclasses should be abstract. Overrides with the code that check if becoming overdraw
21
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 21 Coupled design Suppose you need to add a function to the interface due to new requirements. How can you do it without modifying the AbstractSupplier?
22
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 22 Coupled design you have to modify the abstract supplier maybe clients should be recompiled this new function will have to be implemented in all existing concrete supplier classes or a default implementation can be provided by the abstract supplier Suppose you need to add a function to the interface due to new requirements…
23
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 23 Decoupling the Interface Instead of making abstract supplier as a class, make it as an interface. So, concrete providers are no longer subclasses of abstract supplier, but instead provide realizations of the interfaces. How to do this?
24
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 24 Making an interface
25
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 25 Extending the interface Now we can extend the interface to provide a new operation:
26
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 26 More Design Pattern Factory Method Design Pattern
27
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 27 Back to Duck’orama … more ducks … more quacks … more flying types We used the strategy pattern in the example
28
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 28 Creating a new object How do you have the concret duck objects?... Duck duck; if (picnic) { duck = new MallarDuck(); } else if (hunting) ) { duck = new WildDuck(); } else if (inBathTube) { duck = new RubberDuck(); }... The objects are created according to a context
29
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 29 Problems You might have several places in the system where this kind of code for creating objects is repeated If you need to do a change…... Duck duck; if (picnic) { duck = new MallarDuck(); } else if (hunting) ) { duck = new WildDuck(); } else if (inBathTube) { duck = new RubberDuck(); } duck.showBehaviour();... Does this code follow the open-closed principle?
30
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 30 Identifying what varies We want to encapsulate the code the object creation:... Duck duck; ????? duck.showBehaviour();... if (picnic) { duck = new MallarDuck(); } else if (hunting) ) { duck = new WildDuck(); } else if (inBathTube) { duck = new RubberDuck(); } How can we do this?
31
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 31 Simple solution Move the code to a new class: public class DuckFactory { public Duck createDuck(DuckType t){ Duck duck = null; if (t == picnic) { duck = new MallarDuck(); } else if (t == hunting) ) { duck = new WildDuck(); } else if (t == inBathTube) { duck = new RubberDuck(); } return duck; }
32
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 32 Using the factory Let’s have store of ducks: public class DuckStore { DuckFactory df; public DuckStore(DuckFactory df){ this.df = df; } public Duck getDuck(DuckType t){ Duck duck; duck = df.createDuck(t); duck.showBehaviour();... return duck; }... } The store has the factory to build the ducks. Every time you need a new duck, you just get it from the store.
33
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 33 Example Write the main program using the factory and the store of ducks. public class DuckFactory { public Duck createDuck(DuckType t){ Duck duck = null; if (t == picnic) { duck = new MalarDuck(); } else if (t == hunting) ) { duck = new WildDuck(); } else if (t == inBathTube) { duck = new RubberDuck(); } return duck; } public class DuckStore { DuckFactory df; public DuckStore(DuckFactory df){ this.df = df; } public Duck getDuck(DuckType t){ Duck duck; duck = df.createDuck(t); duck.showBehaviour();... return duck; }... }
34
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 34 Adding new duck types Now it is much easier to inclue a new type of duck, and you only need to change one place: the factory. Draw the class diagram StrangeDuck CoiledDuck WersternDuck USBDuck
35
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 35 More changes Due to the huge success of the game, the company decided to develop a new game, the Duck Raider, with several types of strange ducks. How would you do? Can you reuse the code?
36
Marcelo Santos – OOAD-CDT309, Spring 2008, IDE-MdH 36 Deriving the pattern in the whiteboard
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.