1 Unit 5 Design Patterns: Design by Abstraction. 2 What Are Design Patterns? Design patterns are:...
-
Upload
scarlett-grant -
Category
Documents
-
view
254 -
download
0
Transcript of 1 Unit 5 Design Patterns: Design by Abstraction. 2 What Are Design Patterns? Design patterns are:...
1
Unit 5 Design Patterns: Design by Abstraction
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
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
GoF Patterns
Creational Structural Behavioral
Abstract Factory Adapter Chain of ResponsibilityBuilder Bridge CommandFactory Method Composite InterpreterPrototype Decorator IteratorSingleton Façade Mediator
Flyweight MementoProxy Observer
StateStrategyTemplate MethodVisitor
E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns, Elements of ReusableObject-Oriented Software, Addison-Wesley, 1995.
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
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
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
Refactoring by Inheritance
class A { void m1() { // … step1(); step2(); step3(); // … } // …}
class B { void m2() { // … step1(); step2(); step3(); // … } // …}
Sample code: any duplicate?
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
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
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
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
14
Solution: use of interface flyable & quackable
14
Duck
quack()swim()display()
MallardDuck
fly()quack()display()
RedheadDuckfly()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
16
So pull out the duck behaviors fly & quack
Change the behavior at run time
<<interface>> 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
18
e.g.Duck pond simulation game
18
Duck
FlyBehavior flyBehaviorQuackBehavior quackBehaviorswim()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
20
Question
Have we used the Strategy Pattern before?
21
Example :
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.
23
e.g. Gumball machine state diagram
Insert quarter eject quarter turns crank
gumballs=0
gumballs>0 dispense gumball
Out of Gumballs
No Quarter
Gumballsold
HasQuarter
24
Java programPublic 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;
}
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”);
}
…………………………
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
27
<<interface>> StateinsertQuarter()ejectQuarter()turnCrank()dispense()
SoldStateinsertQuarter()ejectQuarter()turnCrank()dispense()
SoldOutStateinsertQuarter()ejectQuarter()turnCrank()dispense()
NoQuarterStateinsertQuarter()ejectQuarter()turnCrank()dispense()
HasQuarterStateinsertQuarter()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”)
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.
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.
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.
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.
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.
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.
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;
}
}
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<Item> items;
public ShoppingCart(){
this.items=new ArrayList<Item>();
}
37
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);
}
}
38
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
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);
39
cart.addItem(item1);
cart.addItem(item2);
//pay by paypal
cart.pay(new PaypalStrategy("[email protected]", "mypwd"));
//pay by credit card
cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
}
}
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
40
Problems Strategy D P
1. Different types of fonts should be decided at run time
2. On college web site, display separate map of every department as the user selects the department. Dpt: IT,Comp, Mech, electrical, E-TC etc.
3. Racing Game: choose car/ bike of different types at run time.
4. Insurance policies are chosen at run time
41
Problems State D P Draw different states of a PC & its state
diagram. Design using State D P State of a student is defined as regular,
defaulter, YD, ATKT, new admission, direct admission, pass-out etc. Draw a state diagram & design using State D P
Car states: Draw a state diagram & design using State D P
Observer Design Pattern
Also Known As:
Dependents,
Publish-Subscribe,
and confusingly, Model-View
Introduction to Observer
Observer defines a one-to-many or many-to-many dependency between objects.
When the state of one object changes, then all the other objects that are dependent on that object are updated automatically.
Used for event handling where consistency between objects is necessary
General Example
Suppose you have some data that can be displayed by a table, a bar graph or a pie chart.
Changes to the underlying data should be reflected in all three of the displays
This is where the Observer Design Pattern comes in handy.
Motivation for Using
Maintaining consistency between related objects is necessary when a system contains a collection of cooperating classes
This consistency shouldn’t be accomplished through tightly coupling the classes since this reduces the reusability of those tightly coupled classes.
Needs to be scalable. There should also be no limit on the number of objects that depend on one or more other objects.
• You are coding an app in which a weather station updates three objects, one that displays current conditions, one that calcs statistics over time (up to date), and one that makes a forecast.
• Here is the obvious approach:
public class WeatherData {
[declarations and getters/setters omitted]
public void measurements changed(){
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionsDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
}
Freeman, Freeman, Sierra, and Bates, Head First Design Patterns,O’Reilly 2004
Example of the Problem:
public void measurementsChanged(){
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionsDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
Problems:
1. Area that is likely to change is mixed with area that is not likely to change
2. update() calls are coded to concrete objects, not types• 3. Need to change code if the subscribers change
Observer addresses these problems
Problems With The Obvious Approach
Three Major Aspects of Observer
1. The Subject, which is the object being observed
2. The Observer, which observes a Subject
3. Relationship between 1 and 2: attach/detach (or subscribe / unsubscribe) and update
Generalized Structure
Generalized Structure (cont.)
• Subject▫ Interface for ConcreteSubjects▫ Requires implementations to provide at least the following
methods: subscribe / attach unsubscribe / detach notify all observers of state changes
• ConcreteSubject▫ Implements the Subject interface▫ Maintains direct or indirect references to one or more
ConcreteObservers▫ Keeps track of its own state▫ When its state changes it sends a notification to all of its
Observers by calling their update() methods
Generalized Structure (cont.)
Observer Interface for ConcreteObserver objects Requires an update method
ConcreteObserver This is the actual object that is observing the
state of the ConcreteSubject. The state that it maintains should always be
consistent with the state of its Subject. Implements update() method.
Two Ways to Implement Updates
• The Push Model▫ Subject sends all of the necessary information about any of its changes to
all the Observers.▫ Pushes information to the Observer as parameter with the update()
method.▫ Requires assumptions about what the Observers need to know.▫ May need to allow for subscription to relevant changes only, but this adds
complexity
• The Pull Model▫ The Subject sends an indication to the Observer that a change has
occurred.▫ Observers use public methods of Subject to query information they want▫ It is up to the Observer to pull all of the necessary information from the
Subject in order to effect any relevant changes.▫ Subject requires fewer assumptions about what the observers want to
know
General Implementation
Subjects can track Observers through ArrayLists or other data structures.
Observers can track multiple Subjects and get different data from each.
Pull model uses an update method that takes a reference to Subject as a parameter.
The Subject should trigger updates when its state changes.
General ImplementationMethods that change state may call a stateChanged() method:
public void notifyObservers(){for(Observer o: observers)
o.update();
}
public void stateChanged(){// do other things
notifyObservers();
// do whatever else still needs doing
}
public void setMeasurements(arguments….) {// set instance variables first
stateChanged();
}
Simple Example: Swing Button With Listeners
Swing JButtons are Subjects; Listeners are Observers
JButton extends AbstractButton, an abstract class that requires methods to add and remove listeners, as well as several types of notify() methods
ActionListener requires that implementers have actionPerformed() method (update())
Can add as many listeners as you like to JButton, as long as they implement ActionListener
Familiar Example: Swing Button With Listenerspublic class SwingObserverExample{
Jframe frame;
[stuff omitted]
public void go() {
frame = new JFrame();
JButton button = new JButton("Should I do it?");
button.addActionListener(new AngelListener()); button.addActionListener(new DevilListener()); frame.getContentPane().add(BorderLayout.CENTER, button);
[frame property code omitted]
}
// using inner classes in this very simple example
class AngelListener implements ActionListener {
public void actionPerformed(ActionEvent event) { System.out.println("Don't do it");
}
}
class DevilListener implements ActionListener {
public void actionPerformed(ActionEvent event) { System.out.println("Come on, do it!");
}
}
}
When we click the button, both listeners are notified and take action.
Freeman, Freeman, Sierra, and Bates, Head First Design Patterns,O’Reilly 2004, p. 73
Implementation in Java
Java has built-in support for Observer
java.util.Observable class can be extended by a Subject
java.util.Observer interface can be implemented by a class that wants to observe a Subject
UML Diagram for Observable/Observer Classes
Methods in java.util.Observable
• Observable()▫ Creates an Observable object (Subject) with no Observers initially
• setChanged()▫ Indicates that this Subject has changed in some way.
• hasChanged()▫ Returns True if the setChanged() method has been called more recently
than the clearChanged() method. Returns False if otherwise.
• clearChanged()▫ Indicates that this object is done notifying all of its observers of its most
recent changes. It is called automatically by notifyObservers() method
• countObservers()▫ Returns the number of objects that are Observing this Subject.
Methods in java.util.Observable (cont.)
addObserver(Observer o) Adds the passed Observer object to the list
of Observers kept by the Subject deleteObserver(Observer o) /
deleteObservers() Removes the passed Observer object or all
of the Observer objects respectively from the list of Observers kept by the Subject
Methods in java.util.Observable (cont.)
notifyObservers(Object arg) / notifyObservers() If this Subject has changed, this method
notifies all of its Observers and then calls the clearChanged() method. When given an arg as a parameter in the function call, the Observer knows which attribute of the Subject has changed otherwise the Observer can be notified without specifying an arg.
Methods in java.util.Observer
update(Observable o, Object arg) Called when the Subject has changed. o is
the Subject in question, and arg is an argument that can be passed to tell the Observer which attribute of the Subject has changed.
Limitations of Built-In Implementation (Java)
Observable is a class, not an interface Can’t add its behavior to a concrete class that
subclasses something else. Since there is no Observable interface, you can’t
create an impl that works with Observer but doesn’t subclass Observable.
Can’t compose another class that has an Observable since setChanged() is protected
Questions on Observer Pattern
Benefits of the Observer Pattern
Minimal coupling between the Subject and Observer Objects
Many Observers can be added to a Subject without having to modify the Subject.
Reuse of Subjects without needing to also reuse any of their Observers. The opposite also holds true.
The only thing a Subject needs to keep track of is its list of Observers.
The Subject does not need to know the concrete classes of its Observers, only that each one implements the Observer interface
Trouble Spots
o Cascading notifications if Observers update their own clients or if they can also make changes to the Subject
o Repeated notifications when sequences of changes occur.o “Dangling references” to Subjects or Observers when either type are
manually deleted in non-garbage collected environments. Need to notify Observers when Subjects are deleted and vice-versa.
o Subject state must be self-consistent before calling notify(), especially with pull model.
o Careful not to push irrelevant information on observers with push model.
o If update() fails, the Observer won’t know that it missed potentially important information
ADAPTER PATTERN
Winter 2010
Intent
Convert the interface of a class into another interface clients expect.
Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Wrap an existing class with a new interface.
Also Known As-> Wrapper
slide 69
Motivation
Sometimes a toolkit or class library can not be used because its interface is incompatible with the interface required by an application
We can not change the library interface, since we may not have its source code
Even if we did have the source code, we probably should not change the library for each domain-specific application
slide 70
Motivation
Example:
slide 71
Participants
Target (shape) defines the domain-specific interface that Client
uses. Adapter (TextShape)
adapts the interface Adaptee to the Target interface. Adaptee (TextView)
defines an existing interface that needs adapting. Client (DrawingEditor)
collaborates with objects conforming to the Target interface.
slide 72
Structure
A class adapter uses multiple inheritance to adapt one interface to another:
slide 73
Structure
An object adapter relies on object composition:
slide 74
Collaboration
slide 75
Applicability
Use the Adapter pattern when You want to use an existing class, and its
interface does not match the one you need
You want to create a reusable class that cooperates with unrelated classes with incompatible interfaces
slide 76
78
Class adapter
Concrete Adapter class Unknown Adaptee subclasses might cause problem Overloads Adaptee behavior Introduces only one object
Implementation
How much adapting should be done? Simple interface conversion that just
changes operation names and order of arguments
Totally different set of operations Does the adapter provide two-way
transparency? A two-way adapter supports both the Target
and the Adaptee interface. It allows an adapted object (Adapter) to appear as an Adaptee object or a Target object
slide 79
80
Example 1
The classic round pegs and square pegs! Here's the SquarePeg class:
/**
* The SquarePeg class.
* This is the Target class.
*/
public class SquarePeg {
public void insert(String str) {
System.out.println("SquarePeg insert(): " + str);
}
}
81
Example 1 (continued)
And the RoundPeg class:
/**
* The RoundPeg class.
* This is the Adaptee class.
*/
public class RoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}
If a client only understands the SquarePeg interface for inserting pegs using the insert() method, how can it insert round pegs?
A peg adapter!
82
Example 1 (continued)
Here is the PegAdapter class:
/**
* The PegAdapter class.
* This is the Adapter class.
* It adapts a RoundPeg to a SquarePeg.
* Its interface is that of a SquarePeg.
*/
public class PegAdapter extends SquarePeg {
private RoundPeg roundPeg;
public PegAdapter(RoundPeg peg) {this.roundPeg = peg;}
public void insert(String str) {roundPeg.insertIntoHole(str);}
}
83
Example 1 (continued)
Typical client program:
// Test program for Pegs.
public class TestPegs {
public static void main(String args[]) {
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");
84
Example 1 (continued)
// Now we'd like to do an insert using the round peg.
// But this client only understands the insert()
// method of pegs, not a insertIntoHole() method.
// The solution: create an adapter that adapts
// a square peg to a round peg!
PegAdapter adapter = new PegAdapter(roundPeg);
adapter.insert("Inserting round peg...");
}
} Client program output:
SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...
Example 2
Consider that we have a third party library that provides sorting functionality through it's NumberSorter class. This is our Adaptee
/*
* This is our adaptee, a third party implementation of a
* number sorter that deals with Lists, not arrays.
*/
public class NumberSorter
{
public List<Integer> sort(List<Integer> numbers)
{
//sort and return
return new ArrayList<Integer>();
}
}
slide 85
Example 2 (continued)
Our Client deals with primitive arrays rather than Lists. For the sake of this example, lets say we can't change the client to use Lists.
We've provided a Sorter interface that expects the client input. This is our target.
//this is our Target interface
public interface Sorter
{
public int[] sort(int[] numbers);
}
slide 86
Example 2 (continued)
Finally, the SortListAdapter implements our target interface and deals with our adaptee, NumberSorter
public class SortListAdapter implements Sorter
{
@Override
public int[] sort(int[] numbers)
{
//convert the array to a List
List<Integer> numberList = new ArrayList<Integer>();
//call the adapter
NumberSorter sorter = new NumberSorter();
numberList = sorter.sort(numberList);
//convert the list back to an array and return
return sortedNumbers;
}
}
slide 87
Example 2 (Continued)
int[] numbers = new int[]{34, 2, 4, 12, 1};
Sorter sorter = new SortListAdapter();
sorter.sort(numbers);
slide 88
89
Example 3
Notice in Example 1 that the PegAdapter adapts a RoundPeg to a SquarePeg. The interface for PegAdapter is that of a SquarePeg.
What if we want to have an adapter that acts as a SquarePeg or a RoundPeg? Such an adapter is called a two-way adapter.
One way to implement two-way adapters is to use multiple inheritance, but we can't do this in Java
But we can have our adapter class implement two different Java interfaces!
90
Example 3 (continued)
Here are the interfaces for round and square pegs:
/**
*The IRoundPeg interface.
*/
public interface IRoundPeg {
public void insertIntoHole(String msg);
}
/**
*The ISquarePeg interface.
*/
public interface ISquarePeg {
public void insert(String str);
}
91
Example 3 (continued)
Here are the new RoundPeg and SquarePeg classes. These are essentially the same as before except they now implement the appropriate interface.
// The RoundPeg class.
public class RoundPeg implements IRoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole(): " + msg);
}
}
// The SquarePeg class.
public class SquarePeg implements ISquarePeg {
public void insert(String str) {
System.out.println("SquarePeg insert(): " + str);
}
}
92
Example 3 (continued)
And here is the new PegAdapter:
/**
* The PegAdapter class.
* This is the two-way adapter class.
*/
public class PegAdapter implements ISquarePeg, IRoundPeg {
private RoundPeg roundPeg;
private SquarePeg squarePeg;
public PegAdapter(RoundPeg peg) {this.roundPeg = peg;}
public PegAdapter(SquarePeg peg) {this.squarePeg = peg;}
public void insert(String str) {roundPeg.insertIntoHole(str);}
public void insertIntoHole(String msg){squarePeg.insert(msg);}
}
93
Example 3 (continued)
A client that uses the two-way adapter:
// Test program for Pegs.
public class TestPegs {
public static void main(String args[]) {
// Create some pegs.
RoundPeg roundPeg = new RoundPeg();
SquarePeg squarePeg = new SquarePeg();
// Do an insert using the square peg.
squarePeg.insert("Inserting square peg...");
// Create a two-way adapter and do an insert with it.
ISquarePeg roundToSquare = new PegAdapter(roundPeg);
roundToSquare.insert("Inserting round peg...");
94
Example 3 (continued)
// Do an insert using the round peg.
roundPeg.insertIntoHole("Inserting round peg...");
// Create a two-way adapter and do an insert with it.
IRoundPeg squareToRound = new PegAdapter(squarePeg);
squareToRound.insertIntoHole("Inserting square peg...");
}
} Client program output:
SquarePeg insert(): Inserting square peg...
RoundPeg insertIntoHole(): Inserting round peg...
RoundPeg insertIntoHole(): Inserting round peg...
SquarePeg insert(): Inserting square peg...
Related Patterns
The Bridge pattern shares structure with object adapter, but diverges on intent. Bridge is concerned with separating an object's interface from its implementation while adapter changes the interface of an existing object
The Decorator pattern does not change an object's interface, but it does support recursive composition which adapter does not. In this way, Decorator is more flexible than adapter for dealing with functionality additions
slide 95
96
In software engineering, a design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations. Patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Patterns that imply mutable state may be unsuited for functional programming languages, some patterns can be rendered unnecessary in languages that have built-in support for solving the problem they are trying to solve, and object-oriented patterns are not necessarily suitable for non-object-oriented languages.
Design patterns may be viewed as a structured approach to computer programming intermediate between the levels of a programming paradigm and a concrete algorithm.
97
Types Design patterns reside in the domain of modules and interconnections. At a higher
level there are architectural patterns which are larger in scope, usually describing an overall pattern followed by an entire system.[1]
There are many types of design patterns, for instance [citation needed] [2]
Algorithm strategy patterns addressing concerns related to high-level strategies describing how to exploit application characteristics on a computing platform. [
clarification needed]
Computational design patterns addressing concerns related to key computation identification.[clarification needed]
Execution patterns which address issues related to lower-level support of application execution, including strategies for executing streams of tasks and for the definition of building blocks to support task synchronization.
Implementation strategy patterns addressing concerns related to implementing source code to support
program organization, and the common data structures specific to parallel programming.
Structural design patterns addressing concerns related to global structures of applications being developed.
98
Documentation
The documentation for a design pattern describes the context in which the pattern is used, the forces within the context that the pattern seeks to resolve, and the suggested solution.[23] There is no single, standard format for documenting design patterns. Rather, a variety of different formats have been used by different pattern authors. However, according to Martin Fowler, certain pattern forms have become more well-known than others, and consequently become common starting points for new pattern-writing efforts.[24] One example of a commonly used documentation format is the one used by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (collectively known as the "Gang of Four", or GoF for short) in their book Design Patterns. It contains the following sections:
Pattern Name and Classification: A descriptive and unique name that helps in identifying and referring to the pattern.
Intent: A description of the goal behind the pattern and the reason for using it. Also Known As: Other names for the pattern. Motivation (Forces): A scenario consisting of a problem and a context in which this
pattern can be used. Applicability: Situations in which this pattern is usable; the context for the pattern. Structure: A graphical representation of the pattern. Class diagrams and
Interaction diagrams may be used for this purpose. Participants: A listing of the classes and objects used in the pattern and their roles in
the design.
99
DocumentationCONT…
Collaboration: A description of how classes and objects used in the pattern interact with each other.
Consequences: A description of the results, side effects, and trade offs caused by using the pattern.
Implementation: A description of an implementation of the pattern; the solution part of the pattern.
Sample Code: An illustration of how the pattern can be used in a programming language.
Known Uses: Examples of real usages of the pattern. Related Patterns: Other patterns that have some relationship with the pattern;
discussion of the differences between the pattern and similar patterns.