Download presentation
Presentation is loading. Please wait.
Published byHarold Curtis Modified over 9 years ago
1
1 Unit 5 Design Patterns: Design by Abstraction
2
2 What Are Design Patterns? Design patterns are: Schematic descriptions of design solutions to recurring problems in software design, and Reusable (i.e., generic), but don’t have to be implemented in the same way. That is, describe: Design problems that occur repeatedly, and Core solutions to those problems.
3
3 Why Design Patterns? To capture and document software design knowledge. => helps designers acquire design expertise. To support reuse in design and boost confidence in software systems. To provide a common vocabulary for software designers to communicate their designs.
4
4 GoF Patterns Creational StructuralBehavioral Abstract FactoryAdapter Chain of Responsibility Builder BridgeCommand Factory MethodCompositeInterpreter Prototype DecoratorIterator Singleton FaçadeMediator FlyweightMemento ProxyObserver State Strategy Template Method Visitor E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns, Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995.
5
5 Generic Components Generic components Program components (e.g., classes and packages) that can be extended, adapted, and reused in many different contexts without having to modify the source code Also known as reusable components Techniques of designing generic components Refactoring Generalizing
6
6 Refactoring Definition Refactoring means restructuring a program to improve its structure (e.g., to eliminate duplicate code segments) without changing its functionality Approach Identify code segment that implements the same logic (e.g., duplicate code) Capture the logic in a generic component Restructure by replacing every occurrence of the code segment with a reference to the generic component
7
7 Refactoring Duplication Why? Hazardous for maintenance Changes must be repeated everywhere Some may be overlooked or forgotten Thus, code segments can easily drift apart Approach Refactoring by inheritance Refactoring by delegation
8
8 Refactoring by Inheritance class A { void m1() { // … step1(); step2(); step3(); // … } // … } class B { void m2() { // … step1(); step2(); step3(); // … } // … } Sample code: any duplicate?
9
9 Refactored Code class C { void computeAll() { step1(); step2(); step3(); } class A extends C { void m1() { // … computeAll(); // … } // … } class B extends C { void m2() { // … computeAll(); // … } // … }
10
10 Refactoring by Delegation class Helper { void computeAll() { step1(); step2(); step3(); } class A { void m1() { // … h.computeAll(); // … } Helper h; } class B { void m2() { // … h.computeAll(); // … } Helper h; } Q. Compare two approaches of refactoring.
11
11 Strategy Design Pattern Context contextMethod() strategy ConcreteStrategyA algorithm() Strategy alogorithm() ConcreteStrategyB algorithm() Intent To define a family of algorithms, encapsulate each one, and make them interchangeable strategy.algorithm()
12
e.g.Duck pond simulation game 12 Duck quack() swim() display() MallardDuck display() RedheadDuck display() other Duck
13
Add fly() method Solution : add fly() in base class But RubberDuck can’t fly nor quack it can squeak so override quack method & fly method to ‘no fly’ We need to override every method that needs change 13
14
Solution: use of interface flyable & quackable 14 Duck quack() swim() display() MallardDuck fly() quack() display() RedheadDuck fly() quack() display() RubberDuck quack() display() Flyable fly() Quackable quack()
15
No reuse of code as every class has to implement code for the interface Solution: take what varies & “encapsulate” it so it won’t affect the rest of the code Later encapsulated part can be extended without affecting rest of the code All patterns provide a way to let some part of a system vary independently of all other parts 15
16
So pull out the duck behaviors fly & quack Change the behavior at run time 16 > FlyBehavior fly() FlyWithWings fly() { // implements duck flying } FlyNoWay fly() { // do nothing can’t fly }
17
Simi. interface QuackBehavior is implemented by Quack, Squeak & MuteQuack classes Other objects can reuse fly & quack behaviors as these are no longer hidden in Duck class Also we can add new behavior without disturbing existing behaviors 17
18
18 e.g.Duck pond simulation game 18 Duck FlyBehavior flyBehavior QuackBehavior quackBehavior swim() display() performQuack() performFly() setFlyBehavior(FlyBehavior fb) setQuackBehavior(QuackBehavior qb) MallardDuck display() RedheadDuck display() RubberDuck display() Encapsulated Fly behavior Encapsulated Quack behavior
19
Client makes use of an encapsulated family of algorithms for both flying & quacking Favor composition over inheritance Duck class is composed of right behavior object 19
20
20 Question Have we used the Strategy Pattern before?
21
Example : 21
22
State Design Pattern State pattern is one of the behavioral design pattern. State design pattern is used when an Object change its behavior based on its internal state. 22
23
e.g. Gumball machine state diagram Insert quarter eject quarter turns crank gumballs=0 gumballs>0 dispense gumball 23 Out of Gumballs No Quarter Gumball sold Has Quarter
24
Java program Public class GumballMachine { final static int SOLD_OUT=0; final static int NO_QUARTER=1; final static int HAS_QUARTER=2; final static int SOLD=3; int state=SOLD_OUT; int count =0; public void insertQuarter() { if(state==HAS_QUARTER) { SOP(“You can’t insert another quarter”); } else if(state==NO_QUARTER) { SOP(“You inserted a quarter”); state= HAS_QUARTER; } 24
25
else if(state==SOLD_OUT) { SOP(“You can’t insert a quarter, the m/c is sold out”); } else if(state==SOLD) { SOP(“please wait we are already giving a gumball”); } public void ejectQuarter() { if(state==HAS_QUARTER) { SOP(“quarter RETURNED”); } ………………………… 25
26
If want to add new state “WINNER”, every method need to be changed as per new state Instead use interfaces & separate states from code Map each state to a class Similar to strategy design pattern 26
27
27 > State insertQuarter() ejectQuarter() turnCrank() dispense() SoldState insertQuarter() ejectQuarter() turnCrank() dispense() SoldOutState insertQuarter() ejectQuarter() turnCrank() dispense() NoQuarterState insertQuarter() ejectQuarter() turnCrank() dispense() HasQuarterState insertQuarter() ejectQuarter() turnCrank() dispense()
28
If you are in NO_QUARTER state & you invoked 1.inserQuarter() method, set gumballMachinneState=HAS_QuarterState 2. ejectQuarter() SOP(“u havent inserted quarter”) 3. turnCrank() SOP(“There is no quarter”) 4. dispense() SOP(“u to pay first”) 28
29
e.g. TV Remote Suppose we want to implement a TV Remote with a simple button to perform action, if the State is ON, it will turn on the TV and if state is OFF, it will turn off the TV. State Interface First of all we will create State interface that will define the method that should be implemented by different concrete states and context class. State.java package com.journaldev.design.state; public interface State { public void doAction(); } Concrete State Implementations In our example, we can have two states – one for turning TV on and another to turn it off. So we will create two concrete state implementations for these behaviors. 29
30
Context Implementation TVContext.java public class TVContext implements State { private State tvState; public void setState(State state) { this.tvState=state; } public State getState() { return this.tvState; } @Override public void doAction() { this.tvState.doAction(); } } Notice that Context also implements State and keep a reference of its current state and forwards the request to the state implementation. 30
31
TVStartState.java public class TVStartState implements State { @Override public void doAction() { System.out.println("TV is turned ON"); } } TVStopState.java package com.journaldev.design.state; public class TVStopState implements State { @Override public void doAction() { System.out.println("TV is turned OFF"); } Now we are ready to implement our Context object that will change its behavior based on its internal state. 31
32
Test Program Now let’s write a simple program to test our implementation of TV Remote using State pattern. TVRemote.java public class TVRemote { public static void main(String[] args) { TVContext context = new TVContext(); State tvStartState = new TVStartState(); State tvStopState = new TVStopState(); context.setState(tvStartState); context.doAction(); context.setState(tvStopState); context.doAction(); } } Output of above program is same as the basic implementation of TV Remote without using any pattern. The benefits of using State pattern to implement polymorphic behavior is clearly visible, the chances of error are less and its very easy to add more states for additional behavior making it more robust, easily maintainable and flexible. Also State pattern helped in avoiding if-else or switch-case conditional logic in this scenario. 32
33
e.g. of Strategy design pattern For our example, we will try to implement a simple Shopping Cart where we have two payment strategies – using Credit Card or using PayPal. First of all we will create the interface for our strategy, in our case to pay the amount passed as argument. PaymentStrategy.java public interface PaymentStrategy { public void pay(int amount); } Now we will have to create concrete implementations of algorithms for payment using credit/debit card or through paypal. 33
34
PaypalStrategy.java public class PaypalStrategy implements PaymentStrategy { private String emailId; private String password; public PaypalStrategy(String email, String pwd){ this.emailId=email; this.password=pwd; } @Override public void pay(int amount) { System.out.println(amount + " paid using Paypal."); } } Now our algorithms are ready and we can implement Shopping Cart and payment method will require input as Payment strategy. 34
35
Item.java package com.journaldev.design.strategy; public class Item { private String upcCode; private int price; public Item(String upc, int cost){ this.upcCode=upc; this.price=cost; } public String getUpcCode() { return upcCode; } public int getPrice() { return price; } } 35
36
ShoppingCart.java package com.journaldev.design.strategy; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; public class ShoppingCart { //List of items List items; public ShoppingCart(){ this.items=new ArrayList (); } public void addItem(Item item){ this.items.add(item); } public void removeItem(Item item){ this.items.remove(item); } public int calculateTotal(){ int sum = 0; for(Item item : items){ sum += item.getPrice(); } return sum; } public void pay(PaymentStrategy paymentMethod){ int amount = calculateTotal(); paymentMethod.pay(amount); } Notice that payment method of shopping cart requires payment algorithm as argument and doesn’t store it anywhere as instance variable. Let’s test our setup with a simple program. ShoppingCartTest.java shoppingCartTest.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package com.journaldev.design.strategy; public class ShoppingCartTest { public static void main(String[] args) { ShoppingCart cart = new ShoppingCart(); Item item1 = new Item("1234",10); Item item2 = new Item("5678",40); cart.addItem(item1); cart.addItem(item2); //pay by paypal cart.pay(new PaypalStrategy("myemail@example.com", "mypwd")); //pay by credit card cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15")); } } O package com.journaldev.design.strategy; public class CreditCardStrategy implements PaymentStrategy { private String name; private String cardNumber; private String cvv; private String dateOfExpiry; public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){ this.name=nm; this.cardNumber=ccNum; this.cvv=cvv; this.dateOfExpiry=expiryDate; } @Override public void pay(int amount) { System.out.println(amount +" paid with credit/debit card"); } } Output of above program is: 1 2 50 paid using Paypal. 50 paid with credit/debit card 36
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.