Chapter 2
Design Principles and Design Patterns
Object-Oriented Design Principles
OO Design vs. OO Programming
Object-Oriented Design – a method for decomposing software architectures
– based on the objects every system or subsystem manipulates
– relatively independent of the programming language used
Object-Oriented Programming– construction of software systems as
• Structured collection of Abstract Data Types (ADT)
• Inheritance
• Polymorphism
– concerned with programming languages and implementation issues
Polymorphism
Behavior promised in the public interface of superclass objects implemented by subclass objects
– in the specific way required for the subclass
Why Is this Important? – Allow subclasses to be treated like instances of their superclasses
– Flexible architectures and designs• high-level logic defined in terms of abstract interfaces• relying on the specific implementation provided by subclasses • subclasses can be added without changing high-level logic
Signs of Rotting Design
Rigidity ( 僵硬性 ) – code difficult to change
– management reluctance( 拒絶 ) to change anything becomes policy
Fragility ( 易碎性 ) – even small changes can cause cascading effects
– code breaks in unexpected places
Immobility( 固定性 ) – code is so tangled( 糾結 ) that it's impossible to reuse anything
Viscosity( 黏滯性 )
– much easier to hack( 亂砍 ) than to preserve original design
Causes of Rotting Design Changing Requirements
– is inevitable– "All systems change during their life-cycles. This must be borne in mind when
developing systems expected to last longer than the first version". (I. Jacobson, OOSE, 1992)
Dependency Management– the issue of coupling and cohesion– It can be controlled!
• create dependency firewalls• see DIP example
Principle #1
The Open-Closed Principle:
Open-Closed Principle (OCP) "Software Systems change during their life time"
– both better designs and poor designs have to face the changes;
– good designs are stable
Software entities should be open for extension, but closed for modification
B. Meyer, 1988 / quoted by R. Martin, 1996
Be open for extension module's behavior can be extended
Be closed for modification source code for the module must not be changes
Modules should be written so they can be extended
without requiring them to be modified
The Open-Closed Principle OCP attacks software rigidity and fragility!
– When one change causes a cascade of changes The Open-Closed Principle (OCP) states:
– we should attempt to design modules that never need to be changed.
– extend the behavior of the system by adding new code. We do not modify old code
Modules that conform to OCP meet two criteria: Open for Extension - the behavior can be extended to meet new requirements Closed for Modification - the source code of the module is not allowed to change
Abstraction is the Key!
Abstraction– “Denotes the essential characteristics of an object that
distinguish it from all other kinds of objects and thus provides crisply defined conceptual boundaries relative to the perspective of the viewer” -- Grady Booch
Fundamental technique of dealing with complexity Focuses on the outside view of an object and separates
object’s behavior from its implementation
Encapsulation
Encapsulation – “Mechanism used to hide the data, internal structure, and
implementation details of an object. All interaction with the object is through a public interface of operations” -- Craig Larman
Classes should be opaque( 不透明 )
Classes should not expose their internal implementation details
Information Hiding in Java
Use private members and appropriate accessors and mutators when possible
Example:Replace
• public float accuracy;
With private float accuracy; public float getAccuracy ( ) { return (accuracy);} public void setAccuracy (float acc) { accuracy = acc; }
Example: “Closed Client”
Client and Server are concrete classes Client class uses Server class If Client object wants to switch to a different Server object,
what would need to happen?
Client Server
Client code needs to be modified to name the new Server class
Example : “Open Client”
How is this “open” ?
Client AbstractServer
Server
Since the Client depends on the AbstractServer, we can simply switch the Client to using a different Server, by providing a new Server implementation. Client code is unaffected!
Open the door ...
How to make the Car run efficiently with a TurboEngine? Only by changing the Car!
– ...in the given design
... But Keep It Closed!
A class must not depend on a concrete class! It must depend on an abstract class ... ...using polymorphic dependencies (calls)
Strategic Closure "No significant program can be 100% closed "
R.Martin, “The Open-Closed Principle,” 1996
– Closure not complete but strategic
Use abstraction to gain explicit closure– provide class methods which can be dynamically invoked
• to determine general policy decisions
– design using abstract ancestor classes
Use "Data-Driven" approach to achieve closure – place volatile policy decisions in a separate location
• e.g. a file or a separate object
– minimizes future change locations
OCP Heuristics
Changes to public data are always at risk to “open” the module– They may have a rippling effect requiring changes at many unexpected
locations;
– Errors can be difficult to completely find and fix. Fixes may cause errors elsewhere.
Make all object-data privateNo Global Variables!
OCP Heuristics (2)
RTTI is ugly and dangerous– If a module tries to dynamically cast a base class pointer to several derived
classes, any time you extend the inheritance hierarchy, you need to change the module
– recognize them by type switch-es or if-else-if structures
Not all these situations violate OCP all the time– when used only as a "filter"
RTTI is Ugly and Dangerous!
Another OCP Example Consider the following method:
The job of the above method is to total the price of all parts in the specified array of parts.
Does this conform to OCP?
• YES! If Part is a base class or an interface and polymorphism is being used, then this class can easily accommodate new types of parts without having to be modified!
OCP Example (contd.) But what if the Accounting Department now decreed that motherboard parts
and memory parts have a premium applied when figuring the total price?
Would the following be a suitable modification? Does it conform to OCP?
OCP Example - OCP Conformance
No! Every time the Accounting Department comes out with a new pricing policy, we have to modify totalPrice ( ) method. This is not “Closed for modification”
• These policy changes have to be implemented some place, so what is a solution?
• Version 1 - Could incorporate the pricing policy in getPrice ( ) method of Part.
OCP Example (contd.) Here are example Part and Concrete Part classes:
Add method
Code in concrete classes
•Does this work? Is it “closed for modification”?–No. We must now modify each subclass of Part whenever the pricing policy changes!
How to make it “Closed for Modification”
Better idea - have a PricePolicy class which can be used to provide different pricing policies:
OCP Example (contd.)
OCP Example (contd.)
With this solution we can dynamically set pricing policies at run time by changing the PricePolicy object that an existing Part object refers to.
Any other solution?
Both price of a Part and its associated PricePolicy could be stored in a database.
Single Choice Principle
Corollary to OCP
The Single Choice Principle:
Whenever a software system must support a set of alternatives, ideally only one class in the system
knows the entire set of alternatives!
The Open-Closed PrincipleThings to Remember OCP is the heart of OO design
– Well designed code can be extended without modification
– Primary mechanisms: abstraction and polymorphism (and inheritance hierarchies)
– Conformance to this principle yields the greatest level of reusability and maintainability
It is not possible to have all modules of a software system satisfy the OCP, but we need to attempt to minimize the number of modules that do not satisfy it.
Principle #2
The Liskov Substitution Principle:
The Liskov Substitution Principle
Inheritance should ensure that any property proved about supertype objects also holds for subtype objects
B. Liskov, 1987
The key of OCP: Abstraction and Polymorphism Implemented by inheritance How do we measure the quality of inheritance?
Functions that use pointers or references to base classesmust be able to use objects of derived classes
without knowing it.R. Martin, 1996
The Liskov Substitution Principle
The Liskov Substitution Principle (LSP) seems obvious given polymorphism
For example:
public void drawShape (Shape s) { // code here }
The drawShape method should work with any subclass of the Shape superclass (or, if Shape is a Java interface, it should work with any class that implements the Shape interface)
So what is the big deal with LSP?
The Liskov Substitution Principle
If a function does not satisfy the LSP, then it probably makes explicit reference to some or all of the subclasses of its superclass. Such a function also violates the Open-Closed Principle, since it may have to be modified whenever a new subclass is created.
Inheritance Appears Simple
class Bird { // has beak, wings,... public void fly() {…}; // Bird can fly};
class Parrot extends Bird { // Parrot is a bird public void mimic() {…}; // Can Repeat words...};
// ...Parrot mypet;mypet.mimic(); // my pet being a parrot can Mimic()mypet.fly(); // my pet “is-a” bird, can fly
Penguins Fail to Fly!class Penguin extends Bird {
public void fly() {
error (“Penguins don’t fly!”); }
};
void PlayWithBird (Bird abird) {
abird.fly(); // OK if Parrot.
// if bird happens to be Penguin...OOOPS!!
}
Does not model: “Penguins can’t fly”
It models “Penguins may fly, but if they try it is error”
Run-time error if attempt to fly not desirable
Think about Substitutability - Fails LSP
Design by Contract Advertised Behavior of an object:
– advertised Requirements (Preconditions)
– advertised Promises (Postconditions)
When redefining a method in a derivate class, you may only replace its precondition by a weaker one, and
its postcondition by a stronger oneB. Meyer, 1988
Derived class services should require no more and promise no less
int Base::f(int x);// REQUIRE: x is odd// PROMISE: return even int
int Derived::f(int x);// REQUIRE: x is int// PROMISE: return 8
Square IS-A Rectangle?
Should I inherit Square from Rectangle?
Square
?
Another LSP Example
Consider the following Rectangle class:
// A very nice Rectangle class public class Rectangle { private double width; private double height;
public Rectangle (double w, double h) { width = w; height = h; } public double getWidth ( ) { return width;} public double getHeight ( ) { return height;} public void setWidth (double w) { width = w; } public void setHeight (double h) {height = h;} public double area ( ) { return (width * height);} }
LSP Example (contd.)
Assume we need a Square class. Clearly a square is a rectangle, so the Square class should be derived from the Rectangle class.
Observations: A square does not need both a width and a height as attributes, but it will
inherit them from Rectangle anyway. So each Square object wastes a little memory -- but this is not a major concern.
The inherited setWidth ( ) and setHeight ( ) methods are not really appropriate for a Square, since the width and height of a square are identical. So we’ll need to override the methods setWidth ( ) and setHeight ( ).
LSP Example (contd.)
Here’s the Square class: // A Square class public class Square extends Rectangle { public Square (double s) { super (s, s);} public void setWidth (double w) { super.setWidth (w); super.setHeight(w); } public void setHeight (double h) { super.setWidth (h); super.setHeight (h); }}
setWidth ( ) and setHeight ( ) overridden to reflect Square semantics
LSP Example (contd.)
Everything looks good. But consider this function! public class TestRectangle { // Define a method that takes a Rectangle reference. public static void testLSP (Rectangle r) { r.setWidth (4.0); r.setHeight (5.0); System.out.println (“Width is 4.0 and Height is 5.0” + “, Area” +
r.area () ); if (r.area ( ) == 20.0 ){ System.out.println (“Looking good \n”); else System.out.println(“Huh?? What kind of rectangle is this?? \n”); }
LSP Example (Contd.)
public static void main (String args[] ) { // Create a Rectangle and a Square Rectangle r = new Rectangle (1.0, 1.0); Square s = new Square (1.0);
// Now call the testLSP method. According to LSP it should work for either
// Rectangles or Squares. Does it? testLSP ( r ); testLSP (s); }}
LSP Example (contd.)
Test program output: Width is 4.0 and Height is 5.0, so Area os 20.0 Looking good!
Width is 4.0 and Height is 5.0, so Area is 25.0 Huh?? What kind of rectangle is this??
Looks like we violated LSP!
The Problem? The programmer of the testLSP ( ) method made the reasonable assumption
that changing the width of a Rectangle leaves its height unchanged.
Passing a Square object to such a method results in problems, exposing a violation of LSP.
The Square and Rectangle classes look self consistent and valid. Yet a programmer, making reasonable assumptions about the base class, can write a method that causes the design model to break down.
Solutions cannot be viewed in isolation, they must also be viewed in terms of reasonable assumptions that might be made by the users of the design.
The Problem (contd.) A mathematical square might be a rectangle, but a Square
object is a not a Rectangle object, because the behavior of a Square object is not consistent with the behavior of a Rectangle object!
Behaviorally, a Square is not a Rectangle! A Square object is hence not polymorphic with a Rectangle object.
Hint on LSP violation: when simple methods such as the setWidth and setHeight have to be overridden, inheritance needs to be re-examined!
LSP is about Semantics and Replacement
The meaning and purpose of every method and class must be clearly documented– Lack of user understanding will induce de facto ( 事實的 ) violations of
LSP
Replaceability is crucial– Whenever any class is referenced by any code in any system,
any future or existing subclasses of that class must be 100% replaceable– Because, sooner or later, someone will substitute a subclass;
• it’s almost inevitable.
LSP and Replaceability Any code which can legally call another class’s methods
– must be able to substitute any subclass of that class without modification:
Client Service Class
Client
Service Class
Unexpected Subclass
Alternative Solution:
Favor Composition over Inheritance
Composition Method of reuse in which new functionality is obtained by
creating an object composed of other objects The new functionality is obtained by delegating functionality to
one of the objects being composed. Sometimes also called Delegation, Aggregation or Containment
(although some associate different meanings to these) Aggregation - when one object owns or is responsible for another object
and both objects have identical lifetimes (GoF) Aggregation - when one object has a collection of objects that can exist on
their own (UML) Containment - a special kind of composition in which the contained object
is hidden from other objects and access to the contained object is only via the container object (Coad)
Delegation - when one object delegates the execution of a behavior to another object (Bruegge)
Composition
Composition can be – By reference – By value
C++ allows composition by value or by reference Java allows only by reference
Pros and Cons of Composition Advantages
– Contained objects are accessed by the containing class solely through their interfaces
– “Black-box” reuse - internal details of contained objects are not visible
– Good encapsulation– Fewer implementation dependencies– Each class is focused on just one task– Can be defined dynamically at run-time
Disadvantages– Resulting systems often tend to have more objects– Interfaces must be defined carefully in order to use many different
objects as composition blocks
Inheritance
Method of reuse in which new functionality is obtained by extending the implementation of an existing object
The generalization class (superclass) explicitly captures the common attributes and methods
The specialization class (the subclass) extends the implementation with additional attributes and methods
Advantages and Disadvantages of Inheritance Advantages
– New implementation is easy, since most of it is inherited
– Easy to modify or extend the implementation being reused
Disadvantages– Breaks encapsulation, since it exposes a subclass to implementation details
of its superclass
– “White-box” reuse, since internal details of superclass are visible to subclasses
– Subclasses may have to change if the implementation of the superclass changes
– Implementation inherited from superclasses cannot be changed at runtime
Inheritance vs Composition Example
[Adapted from Bruegge] Needed: variant of HashSet that keeps track of the
number of attempted insertions. Solution: subclass HashSet public class NewHashSet extends HashSet {
private int addCount = 0; public NewHashSet (Collection c) { super ( c); } public NewHashSet (int initCap, float loadFactor) { super (initCap, loadFactor); }
Example (contd.)
public boolean add (Object o) { addCount++; return super.add (o); } public boolean addAll (Collection c) { addCount += c.size (); return super.addAll ( c ); } public int getAddCount ( ) { return addCount; }}
Modifications to the HashSet
Example (contd.) Looks good! Or not??? Test:
public static void main (String[] args) {
NewHashSet s = new NewHashSet ( ); s.addAll (Arrays.asList(new String[] {“Snap”, “Crackle”,
“Pop”})); System.out.println(s.getAddCount () ); }
• We get a result of 6, not the expected 3. Why?
• Its because the internal implementation of addAll () in the HashSet superclass itself invokes the add ( ) method.
Inheritance vs Composition
Several ways to fix this -- but note the fragility of the design -- Implementation of the superclass effects the operation of the subclass.
Best fix - use composition– Write a NewSet class that is composed of a Set object. The
NewSet will duplicate the Set interface, but all Set operations will be “forwarded” to the contained Set object
– NewSet is known as a wrapper class - “wraps” an instance of the Set object
– “Delegation through composition” or simply “Delegation”
Example -- Take 2 public class NewSet implements Set { private final Set s; private int addCount = 0; public NewSet (Set s) { this.s = s; } public boolean add (Object o) { addCount++; return s.add(o); } public boolean addAll (Collection c) { addCount += c.size; return s.addAll ( c) ; } public int getAddCount ( ) {return addCount;} //forwarding methods (rest of the Set Interface methods)}
Things to Note
Several things to note:– This class is a Set– It has one constructor whose argument is a Set– The contained Set object can be an object of any class that
implements the Set interface, not just a HashSet– Very flexible -- can wrap any preexisting Set object
Example: List list = new ArrayList ( ); Set s1 = new NewSet (new TreeSet (list)); int capacity = 7; float loadFactor = .66f; Set s2 = new NewSet (new HashSet (capacity, loadFactor));
Some Rules
Use inheritance only when all of the following criteria are satisfied:– A subclass expresses “is a special kind of” and not “is a role
played by a”– An instance of a subclass never needs to become an object of
another class– A subclass extends, rather overrides or nullifies, the
responsibilities of the superclass– A subclass does not extend the capabilities of what is merely a
utility class– Within the problem domain, specializes a role, transaction or
device
The Liskov Substitution Principle The Liskov Substitution Principle (LSP) makes it clear that the
ISA relationship is all about behavior In order for the LSP to hold (and with it the Open-Closed
Principle) all subclasses must conform to behavior that the clients expect of the base classes they use.
A subtype must have no more constraints than its base type, since the subtype must be usable anywhere the base type is usable
If the subtype has more constraints than its base type, there would be uses that would be valid for the base type, but that would violate one of the extra constraints of the subtype and thus violate the LSP!
The guarantee of the LSP is that a subclass can always be used wherever its base class is used!
Principle# 3
The Dependency Inversion Principle
The Dependency Inversion Principle
I. High-level modules should not depend on low-level modules.
Both should depend on abstractions.
II. Abstractions should not depend on details.
Details should depend on abstractionsR. Martin, 1996
OCP states the goal; DIP states the mechanism
A base class in an inheritance hierarchy should not know any of its subclasses
Modules with detailed implementations are not depended upon, but depend themselves upon abstractions
Why “Inversion” ?
Traditional functional programming:– High level modules: business/application rules
– Low level modules: implementation of the business rules
– High level modules complete their functionality by calling/invoking the low level implementation provided by the low level modules
• High level depends on the lower level
Policy layer
Mechanism layer
Utility layer
What are the Implications?
1. Dependency is transitive: Changes in the lower level modules can have direct effects on the higher level modules, forcing them to change in turn.• Absurd! High level modules should be driving change not the other way
round.2. Reuse: We should be able to reuse the high level, policy setting modules
• (pretty good already at reusing the lower level implementations -- libraries)
• Difficult to reuse higher level modules when they depend on lower level details
3. Conclusions:– Strive for having higher level modules be independent of the lower level
modules– Principle is at the heart of framework design!
Inversion of Ownership
Each high level module declares an abstract interface for the services it needs
Lower level layers are realized using through the abstract interface
Here:– Upper level layers do not depend on the lower level modules
– Lower layers depend on the abstract service layers declared in the upper layers!
Procedural vs. OO Architecture
Procedural Architecture
Object-Oriented Architecture
Better “inverted” Design Design applies DIP (1).Inversion of Ownership!
The client “owns” the interface Their “services” derive from the: the utility libraries don’t own the interfaces they implement.
Sometimes called the Hollywood principle: “Don’t call us, we’ll call you!”Advantages:
Policy Layer is now unaffected by changes in the Utility LayerPolicy Layer is now reusable!Inverting Dependencies breaks:
Transitive dependencyDirect dependency in most cases
Provides design that is more flexible, durable and mobile!
Policy
Policy Layer<< interface >>Policy Service Interface
Mechanism
MechanismLayer
<< interface >> Mechanism Service Interface
Utility
UtilityLayer
Why Inversion?
HighLevel
AbstractInterface1<<Interface>>
AbstractInterface2<<Interface>>
AbstractInterface3<<Interface>>
DetailImpl1 DetailImpl2 DetailImpl3
Depend on Abstractions (1/2)
Naïve but powerful principle– Should not depend on concrete classes– All relationships in a program must terminate at an abstract class or
interface According to this heuristic:
– No variable should hold a pointer or reference to a concrete class– No class should derive from a concrete class– No method should override an implemented method of any of its base
classes This heuristic is violated at least once in every program
– Classic example: use of String class– If a concrete class is non-volatile, ignore this heuristic
Depend on Abstractions (2/2)
Most classes “we” write for our programs are volatile -- principle should be applied here.
Not a complete solution -- – Interface of volatile class may change, – May cause propagation of change to abstract interface
it implements– Naïve!
DIP Related Heuristic
Use inheritance to avoid direct bindings to classes:
Design to an interface, not an implementation!
Client
Interface(abstract class)
Implementation(concrete class)
Design to an Interface
Abstract classes/interfaces:– tend to change much less frequently
– abstractions are ‘hinge points’ where it is easier to extend/modify
– shouldn’t have to modify classes/interfaces that represent the abstraction (OCP)
Exceptions– Some classes are very unlikely to change;
• therefore little benefit to inserting abstraction layer
• Example: String class
– In cases like this can use concrete class directly• as in Java or C++
DIP Related Heuristic
Avoid structures in which higher-level layers depend on lower-level abstractions:– In example below, Policy layer is ultimately dependant on Utility layer.
Avoid Transitive Dependencies
Policy Layer
MechanismLayer
UtilityLayer
Depends on Depends on
Solution to Transitive Dependencies
Use inheritance and abstract ancestor classes to effectively eliminate transitive dependencies:
Policy Layer
MechanismLayer
UtilityLayer
depends on
depends on UtilityInterface
MechanismInterface
DIP - Related Heuristic
If you cannot find a satisfactory solution for the class you are designing, try delegating responsibility to one or more classes:
When in doubt, add a level of indirection
Problem Holder
ProblemSolver
When in doubt ... It is generally easier to remove or by-pass existing
levels of indirection than it is to add them later:
XSo, Blue class re-implements some or all of green class’s responsibilities for efficiency and calls red object directly
Blue class’s indirect message calls to red class fail to meet some criteria (e.g. real-time constraints, etc.)
DIP Example Dependency Inversion Principle can be applied whenever one class
sends a message to another. Consider the case of a Button and Lamp object.
– Button:• senses the external environment• receives poll message• Determines whether or not user has “pressed” it.
– Lamp:• Affects the external environment• On receiving turnOn message, illuminates the light• On receiving turnOff message, extingishes the light.
Actual physical mechanism for the Lamp and the Button is irrelevant.
Naïve Design
public class Button { private Lamp itsLamp; public Button (Lamp l) { itsLamp = l;}
public void poll ( ){ if (/* some condition*/) itsLamp.turnOn ( ); else itsLamp.turnOff ( ); }
}
public class Lamp { public void turnOn ( ); public void turnOff ( ); }
Button Lamp
+ poll ( ) + turnOn ( )+ turnOff ()
Why is this a naïve design?
Why is the design naïve?
The dependency between Lamp and Button implies that Lamp cannot be modified without changing (at least recompiling) the
Also - not possible to reuse the Button class to control a Motor/Portal object.
The Button and Lamp code violates the DIP.
Applying DIP (a)
Button
Lamp
+ poll ( )
<< interface >>Button Server
+ turnOn ( )+ turnOff ()
Adding More Abstraction
If there can be multiple types of buttons or switching devices, abstraction can used to further refine the design!
Button(Abstract)
ButtonClient(Abstract)
Button (Implementation)
Lamp
DIP-Conforming Code public abstract class ButtonClient { public abstract void turnOn ( ); public abstract void turnOff ( ); };
public abstract class Button { protected ButtonClient bc; Button (ButtonClient b) { bc = b; } public abstract boolean getState ( ); public void detect ( ) { boolean buttonOn = getState ( ); if (buttonOn) bc.turnOn ( ); else bc.turnOff ( ); } }
public class Lamp extends ButtonClient { public void turnOn ( ) { //code } public void turnOff ( ) { // code} }
public class ButtonImplementation extends Button {
ButtonImplementation (ButtonClient b)
{ super(b); } public boolean getState ( ) { // code} }
The Dependency Inversion Principle One motivation behind the DIP is to prevent you from depending upon
volatile modules.– Typically, concrete classes/methods change frequently, while abstract
classes/methods change are more stable. Abstractions are “hinge points” -- they represent the places where the
design can bend or be extended, without the abstractions themselves being modified (OCP)
One of the most common places that designs depend upon concrete classes is when those designs create instances. By definition, you cannot create instances of abstract classes. Thus to create instances you must depend on concrete classes!– An elegant solution to this problem - Abstract Factory Pattern
Corollary: if a class/modules are concrete but extremely stable this principle can be relaxed.
The Founding Principles
The three principles are closely related
Violating either LSP or DIP invariably results in violating OCP– LSP violations are latent violations of OCP
It is important to keep in mind these principles to get most out of OO development...
Design Patterns
Patterns of Learning
Successful solutions to many areas of human endeavor are deeply rooted in patterns– In fact, an important goal of education is
transmitting patterns of learning from generation to generation
Learning to develop good software is similar to learning to play good chess!
Becoming a Chess Master First learn the rules
– e.g., names of pieces, legal movements, chess board geometry and orientation etc.
Then learn the principles– e.g., relative value of certain pieces, strategic value of
center squares, power of a threat etc. However, to become a master of chess, one must
study the games of other masters– These games contain patterns that must be understood,
memorized and applied repeatedly There are hundred of these patterns
Becoming a Software Design Master First learn the rules
– e.g., the algorithms, data structures and languages of software Then learn the principles
– e.g., structured programming, modular programming, object-oriented programming, generic programming, principles of OO etc.
However, to become a master of software design, one must study the designs of other masters– These designs contain patterns that must be understood,
memorized and applied repeatedly There are hundred of these patterns
What is a Pattern ?
Each pattern describes a problem
which occurs over and over again in our environment,
and then describes
the core of the solution to that problem,
in such a way that
you can use this solution a million times over,
without ever doing it the same way twice
C. Alexander, “The Timeless Way of Building”, 1979
Why Use Patterns ?
An additional layer of abstraction– separate things that change from things that stay the same– distilling out common factors between a family of similar problems– similar to design
Insightful and clever way to solve a particular class of problems– most general and flexible solution
Patterns help you learn from other’s successes, instead of your own failures
Mark Johnson (cited by B. Eckel)
Design Patterns Design patterns represent solutions to problems that arise
when developing software within a particular context– Patterns = Problem/Solution pair in Context
Capture static and dynamic structure and collaboration among key participants in software designs– key participant – major abstraction that occur in a design problem– useful for articulating the how and why to solve non-functional forces.
Facilitate reuse of successful software architectures and design– i.e. the “design of masters”… ;)
Gang of Four (GoF)
Erich Gamma, Richard HelmRalph Johnson & John Vlissides
Design Patterns – Elements ofReusable Object-Oriented Software
Addison-Wesley, 1995.(As CD, 1998)
First systematic software pattern description.
Design Pattern Catalog - GoF
Purpose
Creational Structural Behavioral
Class Factory Method Adapter Interperter
ScopeObject
AbstractFactory
Builder Prototype Singleton
Adapter Bridge Composite Decorator Facade Flyweight Proxy
Chain of Responsibility Command Iterator Mediator Momento Observer State Strategy Vistor
Benefits of Design Patterns Inspiration
– patterns don't provide solutions, they inspire solutions– Patterns explicitly capture expert knowledge and design tradeoffs and
make this expertise widely available– ease the transition to object-oriented technology
Patterns improve developer communication– pattern names form a vocabulary
Help document the architecture of a system– enhance understanding
Design patterns enable large-scale reuse of software architectures
The Strategy Pattern
Long time ago….
It started with a simple SimUDuck app– Simulation can show a large variety of duck species
swimming and making quacking sounds.
Duck quack( ) swim ( ) display ( ) // Other duck like methods
MallardDuckdisplay ( ) { // looks like a mallard }
RedHeadDuckdisplay ( ) { // looks like a redhead}
All ducks quack () and swim (), the superclass takes care of the implementation code.
Each duck subype is responsible for implementing its own display () behavior for how it looks on the screen.
The display ( ) method is abstract, since all duck types look different.
Lots of other types of ducks inherit from the Duck class.
But now we need the ducks to fly…
No problem!
Duck quack( ) swim ( ) display ( ) fly ( ) // Other duck like methods
MallardDuckdisplay ( ) { // looks like a mallard }
RedHeadDuckdisplay ( ) { // looks like a redhead}
All subclasses inherit fly ( )
But something went horribly wrong..
At a demo the program failed to impress anyone -- there were rubber ducks flying across the screen!
What happened? – A localized update to the code caused a non-local side effect (flying rubber
ducks)
Duck quack( ) swim ( ) display ( ) fly ( ) // Other duck like methods
MallardDuckdisplay ( ) { // looks like a mallard }
RedHeadDuckdisplay ( ) { // looks like a redhead}
By putting the fly ( ) in the superclass, ALL ducks got the ability to fly including those that shouldn’t!
RubberDuck quack () { // overridden to Squeak }display ( ) { // looks like a rubberduck }
A Solution
Can override the fly ( ) method similar to the quack ( ) method. fly ( ) {
Do nothing}
What would happen if we added a DecoyDuck to the class hierarchy? It doesn’t quack ( ) or fly ( ).
What else could you try?
How about an interface?
Need a cleaner way to make some (but not all) ducks fly or quack.– Could take the fly ( ) out of the superclass and make an Flyable interface
with a fly ( ) method, and maybe a Quackable interface as well.
Duck swim ( ) display ( )// Other duck like methods
MallardDuckdisplay ( ) { // looks like a mallard }
RedHeadDuckdisplay ( ) { // looks like a redhead}
RubberDuck quack () { // overridden to Squeak }display ( ) { // looks like a redhead}
<<interface>>
Flyable
fly ( )
<<interface>>
Quackable
quack ( )
What do you think about this design?
What do you think?
Dumb!!!! “Duplicate code” all over the place. A small change to the flying
behavior will require changing all 48 of the Duck subclasses!
And what is the one thing that you can count on it software development?
CHANGE!Separate what varies - separate what changes from what stays
constant.
1. We know that fly ( ) and quack ( ) are the parts of the Duck class that vary across ducks.
2. To separate these behaviors from the Duck class, we’ll pull both methods out of the Duck class and create a new set of classes to represent each behavior.
Separating what varies
The Duck class is still the superclass of all ducks, but we are pulling out the fly( ) and quack ( ) behaviors and putting them into another class structure.
Now flying and quacking each get their own set of classes.
Various behavior implementations are going to live here.
Duck Behaviors
Pull out what varies
Duck behaviors will now live in a separate class -- a class that implements a particular behavior interface.That way duck classes won’t need to know any of the implementation details of their own behaviors. But how???
DP: Program to an Interface, not an Implementation
<<interface>> FlyBehavior
fly ( )
FlyWithWings
fly ( ) { // implements duck flying }
FlyNoWay
fly ( ) { // do nothing - can’t fly }
Here we have an interface that all flying classes implement. All new flying classes just need to implement the fly method.
Here’s the implementation of flying for all ducks with wings.
Implementation for all ducks that can’t fly.
We can have a similar implementation hierarchy for the Quackable behavior.
We can now also add new behaviors without modifying any of our existing classes or touching any of the Duck classes that use flying behavior. --- We get REUSE without all the baggage of inheritance.
Integrating Duck Behavior
Key is delegation - we now delegate the quacking and flying behaviors to methods defined in other classes - QuackBehavior and FlyingBehavior
Duck
FlyBehavior flyBehavior
QuackBehavior quackBehavior
performQuack ( )
swim ( )
display ( )
performFly ( )
// other duck-like methods
The behavior variables are declared as the behavior INTERFACE type.
These replace the fly ( ) and quack ( ) methods.
Instance variables hold a reference to a specific behavior at runtime.
public class Duck { QuackBehavior quackBehavior; // other stuff
public void performQuack ( ){ quackBehavior.quack ( ); }}
Delegation
Putting it together…. public class MallardDuck extends Duck { public MallardDuck ( ) { quackBehavior = new Quack ( ); flyBehavior = new FlyWithWings ( ); } } public class Quack implements QuackBehavior { public void quack ( ){ System.out.println (“Quack”); } }
public class FlyWithNoWings impelments FlyBehavior { public void fly ( ){ System.out.println (“I can’t fly” ); }} public class MiniDuckSimulator { public static void main (String[] args) { Duck mallard = new MallardDuck ( ); mallard.performQuack ( ); mallard.performFly ( ); }}
With your knowledge of factories, these would probably not be hardcoded!
Setting Behavior Dynamically! public void setFlyBehavior (FlyBehavior fb) { flyBehavior = fb; } public void setQuackBehavior (QuackBehavior qb) { quackBehavior = qb; }
public class ModelDuck extends Duck { public class ModelDuck { flyBehavior = new FlyNoWay () ;
quackBehavior = new Quack ( ); } public void display ( ) { System.out.println(“I’m a model duck”); }}
public class FlyRocketPowered implements FlyBehavior { public void fly ( ) { System.out.println(“I’m flying with a rocket”); } }
// test it out in main Duck model = new ModelDuck ( ); model.performFly ( ); model.setFlyBehavior (new FlyRocketPowered ( )); model.performFly ( );
Adding a couple of new methods to the Duck class
Create a new type of Duck
Make a new FlyBehavior type
What do you think happens? -- Changing the Duck’s behavior at runtime!
The Strategy Design PatternThe Strategy Design Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithms vary independently from the clients that use it.
Strategy AlgorithmInterface ( )
Context ContextInterface ( )
ConcreteStrategyA AlgorithmInterface ( )
ConcreteStrategyB AlgorithmInterface ( )
ConcreteStrategyC AlgorithmInterface ( )
Context manages the data structures that a concrete strategy operates on.
ConcreteStrategy classes provide the implementations of the different strategies. These operate on the data structures in the the Context, and can be set dynamically.
Defines the generic interface
Summary
Strategy pattern allows selection of one of several algorithms dynamically.
Algorithms may be related via an inheritance hierarchy or unrelated [must implement the same interface]
Strategies don’t hide everything -- client code is typically aware that there are a number of strategies and has some criteria to choose among them -- shifts the algorithm decision to the client.
Observer Pattern
Keeping your Objects in the Know!
The Weather-O-Rama!
Humidity Sensor Device
Temperature Sensor Device
Pressure Sensor Device
Weather Station
Pulls data Displays
Current conditions is one of three different displays. The user can also get weather stats and a forecast.
Display Device
Current Conditions
Temp: 72Humidity: 60Pressure:
Weather-O-Rama provides
What we implement
The Job: Create an app that uses the WeatherData object to update three displays for current conditions, weather stats, and a forecast.
The WeatherData class
WeatherData
getTemperature ( ) getHumidity ( ) getPressure ( ) measurementChanged ( )
// other methods
These three methods return the most recent weather measurements for temperature, humidity, and pressure respectively.
We don’t care HOW these variables are set; the WeatherData object knows how to get updated information from the Weather Station
/* * This method gets called whenever the * measurements have been updated. * / public void measurementsChanged ( ){ // Your code goes here }
A clue: what we need to add!
The Specs so far The WeatherData class has getter methods for three
measurement values: temperature, humidity, and pressure.
The measurementsChanged ( ) method is called anytime new weather measurement data is available. (We don’t know or care how this method is called; we just know that it is)
We need to implement three display elements that use the weather data: a current conditions display, a statistics display, and a forecast display. These displays must be updated each time WeatherData has new measurements.
The system must be expandable -- other developers can create new custom display elements and users can add or remove as many display elements as they want to the application.
A First Misguided Attempt at the Weather Station
public class WeatherData {// instance variable declarationspublic 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); } // other WeatherData methods here}
Grab the most recent measurements by calling the WeatherData’s getter methods (already implemented)
Now update the displays.
Call each display element to update its display, passing it the most recent measurements.
What’s wrong with the first implementation?
public class WeatherData {// instance variable declarationspublic 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); } // other WeatherData methods here}
Area of change, we need to encapsulate this.
At least we seem to be using a common interface to talk to the display elements…they all have an update ( ) method that takes temp, humidity and pressure values.
By coding to concrete implementations we have no way to add or remove other display elements without making changes to the program.
Time for the Observer!
The Newspaper or Magazine subscription model:– A newspaper publisher goes into business and begins
publishing newspapers
– You subscribe to a particular newspaper, and every time there is a new edition, its gets delivered to you. As long as you remain a subscriber, you get new newspapers.
– You unsubscribe when you don’t want the newspapers anymore -- and they stop being delivered
– While the publisher remains in business people, hotels, airlines etc constantly subscribe and unsubscribe to the newspaper.
Publishers + Subscribers = Observer Pattern
Publisher == Subject Subscribers == Observers
int
2
Observer Objects
The observers have subscribed to the Subject to receive updates when the subject’s data changes.
When data in the Subject changes, the observers are notified.
2
2
2
New data values are communicated to the observers in some form when they change.
This object isn’t an observer so it doesn’t get notified when the subject’s data changes.
Subject object manages some data.
The Observer Pattern DefinedThe Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
int
2
Observer Objects
2
2
2
One to many relationship (Subject can have many observers)
Object that holds state
Dependent objects(observers are dependent on the subject to update them when data changes.) Automatic update/notification
Observer Class DiagramHere’s the Subject interface. Objects use this interface to register as observers and also to remove themselves from being observers.
Each subject can have many observers
All potential observers need to implement the Observer interface. This interface has just one method, update ( ), that gets called when the Subject’s state changes.
Concrete observers can be any class that implements the Observer interface. Each observer registers with a concrete subject to receive updates.
The concrete subject may also have methods for setting and getting its state.
A concrete subject always implements the Subject interface. In addition to the register (attach) and remove (detach) methods, the concrete subject implements a notify() method to notify observers whenever state changes.
ForecastDisplay
update ( ) display ( ) { // display the forecast }
Designing the Weather Station
<<interface>> Subject
registerObservers ( ) removeObservers ( ) notifyObservers ( )
<<interface>> Observer
update ( )
observers
WeatherData
registerObservers ( ) removeObservers ( ) notifyObservers ( )
getTemperature ( ) getHumidity ( ) getPressure ( ) measurementsChanged ( )
CurrentConditions
update ( ) display ( ) { // display current measurements }
StatisticsDisplay
update ( ) display ( ) { // display avg, min, and max measurements }
<<interface>> DisplayElement
display ( )
Subject interfaceAll weather components implement the Observer interface. This gives the subject a common interface to talk to when it comes time to update.
Create an interface for all display elements to implement. The display elements just need to implement a display ( ) method.
WeatherData now implements the Subject interface.
Implementing the Weather Station public interface Subject { public void registerObserver (Observer o); public void removeObserver (Observer o); public void notifyObservers ( );}
public interface Observer { public void update (float temp, float humidity, float pressure); }
public interface DisplayElement { public void display ( ); }
Both of these methods take an Observer as an argument, that is the Observer to be registered or removed.
This method is called to notify all observers when the Subject’s state has changed.
The Observer interface is implemented by all observers, so they all have to implement the update ( ) method.
These are the state values the Observers get from the Subject when a weather measurement changes.
The DisplayElement interface just includes one method, display ( ), that we will call when the display element needs to be displayed.
Implementing the Subject Interface in WeatherData public class WeatherData implements Subject { private ArrayList observers;
private float temperature;private float humidity;private float pressure;
public WeatherData ( ){ observers = new ArrayList ( );
} public void registerObserver (Observer o) {
observers.add(o);}
public void removeObserver (Observer o) { int j = observer.indexOf(o); if (j >= 0) { observers.remove(j); } }public void notifyObservers ( ) { for (int j = 0; j < observers.size(); j++) {
Observer observer = (Observer)observers.get(j);observer.update(temperature, humidity, pressure);
}}public void measurementsChanged ( ) { notifyObservers ( ); }// add a set method for testing + other methods.
}
Added an ArrayList to hold the Observers, and we create it in the constructor
Notify the observers when measurements change.
Here we implement the Subject Interface
The Display Elements public class CurrentConditionsDisplay implements Observer, DisplayElement {
private float temperatue;private float humidity;private Subject weatherData;
public CurrentConditionsDisplay (Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver (this);}public void update (float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity;
display ( );}public void display ( ){ System.out.println(“ Current conditions : “ + temperature + “ F degrees and “ + humidity + “ % humidity” );}
}
Implements the Observer and DisplayElement interfaces
The constructors passed the weatherData object (the subject) and we use it to register the display as an observer.
When update ( ) is called, we save the temp and humidity and call display ( )
The display ( ) method just prints out the most recent temp and humidity.
Using Java’s Built-in Observer Pattern Java has built-in support in several of its APIs for the Observer pattern Most general: Observer interface and the Observable class in the
java.util package.– Observer == Observer– Observable == Subject
Observable
addObserver ( ) deleteObserver ( ) notifyObservers ( ) setChanged ( )
WeatherData
getTemperature ( ) getHumidity ( ) getPressure ( )
<<interface>> Observer update ( )
GeneralDisplay update ( ) display ( )
StatisticsDisplay update ( ) display ( )
ForecastDisplay update ( ) display ( )
The Observable class keeps track of all your observers and notifies them for you.
Should be familiar -- same as before!
Some changes to the update ( ) method but basically the same.
Observable is a CLASS not an interface, so WeatherData extends it!
This doesn’t look familiar -- we will see it shortly.
WeatherData does not need to implement register, remove and notify -- it inherits them
Using Java’s Built-in Observer Pattern For an Object to become an Observer:
– Implement the Observer interface (this time the java.util.Observer interface) and call addObserver ( ) on any Observable object. To remove use deleteObserver ( ) method.
For the Observable to send notifications– Become an Observable by extending java.util.Observable
superclass– Then a 2 step process:
1. First call the setChanged ( ) method to signify that the state has changed in your object.
2. Then call one of two notifyObservers ( ) methods– notifyObservers ( ) or notifyObservers (Object arg)
For the Observer to receive notifications– Implement the update ( ) method as before. Signature a bit different.– update (Observable o, Object arg)
This takes an arbitrary data object that gets passed to each Observer when it is notified.
Subject that send the notification.
The setChanged ( ) Method The setChanged ( ) method is used to signify that the state has changed and that
notifyObservers (), when it is called, should update its observers.– If notifyObservers( ) is called without first calling the setChanged ( ), the observers
will NOT be notified. Pseudocode: setChanged ( ){
changed = true;}notifyObservers ( Object arg ){ if (changed ) { for every observer on the list {
call update(this, arg);
} changed = false; } } notifyObservers ( ) { notifyObservers (null); }
The setChanged() method sets the changed flag to true
notifyObserver ( ) only notifies its observers if the changed flag is true.
And after it notifies the observers it sets the changed flag back to false.
Why is the setChanged ( ) necessary? setChanged ( ) method is there to give you more
flexibility– Optimize the notifications
– Example: • if the sensors are sensitive readings may fluctuate by a few tenths of
the a degree.
• May not want to update the observers with every fluctuation
• setChanged ( ) allows you to control the notification points.
Other relevant methods in Observable:– clearChanged ( )
– hasChanged ( )
The notify ( ) -- Push and Pull Methods public void measurementsChanged ( ) {
setChanged ( );notifyObservers ( );
}
public void measurementsChanged ( ){setChanged ( );notifyObservers (this);
}
We first call the setChanged ( ) to indicate that the state has changed.
We aren’t sending a data object with the notifyObservers ( ) call. The Observers are aware of the subject and they will use that to “pull” the latest information from the subject.
A “push” method -- the modified data is being pushed to the observers.
The Dark Side of the java.util.Observable Doesn’t the java.util.Observable violate OO design principle
of programming to interfaces and not implementations?
Yes it does! Observable is a class and not an interface. Moreover it does not even implement an interface.
java.util.Observable has a number of problems that limit its usefulness and reuse
1) Observable is a class: you have to subclass it => you can’t add on the Observable behavior to an existing class that already extends another superclass. This limits its potential reuse.
2) There isn’t an Observable interface so you cannot provide your own implementation or swap out the Observable implementation with say a multithreaded implementation
3) Observable protects crucial methods: setChanged () is protected. It means that you cannot call setChanged unless you have subclassed Observable. Violates : favor composition over inheritance!
Other places to find Observer Pattern in Java Both JavaBeans and Swing also provide
implementations of the Observer pattern Look under the hood of JButton’s super class
AbstractButton– Has many add/remove listener methods: allow you to add and
remove observers (called listeners in Swing)– These “listeners” are available for various types of events that
occur on the Swing component– Example: ActionListener lets you “listen in” on any types
of actions that might occur on a button -- like a button press. Also check out the PropertyChangeListener in
JavaBeans
Summary OO Principle in play: Strive for loosely coupled designs between objects that
interact. Main points:
– The Observer pattern defines a one to many relationship between objects– Subjects (observables), update Observers using a common interface– Observers are loosely coupled in that the Observable knows nothing about them,
other than they implement the Observer interface.– You can push or pull data from the Observable when using the pattern (“pull” is
considered more correct)– Don’t depend on a specific order of notification for your Observers– Java has several implementations of the Observer Pattern including the general
purpose java.util.Observable– Watch out for issues with java.util.Observable– Don’t be afraid to create our own version of the Observable if needed– Swing makes heavy use of the Observer pattern, as do many GUI frameworks– You find this pattern in other places as well including JavaBeans and RMI.
The Decorator Pattern
“Decorating Objects -- Power of Extension at Runtime”
Welcome to Starbuzz Coffee! Brief Intro: Starbuzz Coffee has made a name for itself as the fastest growing
coffee shop. Because they have grown so quickly, they are scrambling to update their ordering system to match their beverage offerings….
Beverage description getDescription ( ) cost ( ) // other useful methods
HouseBlend cost ()
DarkRoast cost ()
Decaf cost ()
Expresso cost ()
Beverage is an abstract class, subclassed by all beverages offered in the coffee shop.
The description instance variable is set in each subclass and holds a description of the beverage like: “Most Excellent Dark Roast”.
The cost ( ) method is abstract; subclasses need to define their own implementations.
Each subclass implements cost ( ) to return the cost of the beverage
Adding on…. In addition to your coffee you can also ask for several condiments like steamed
milk, soy, mocha etc. Starbuzz charges a bit for each of these so they really need to get them built into the order system. First attempt…..
DarkRoastWithSoyAndMocha cost ()
DarkRoastWithSteamedMilkAndMocha cost ()
HouseBlend cost ()
Beverage description getDescription ( ) cost ( ) // other useful methods
HouseBlendWithSteamedMilkandMocha cost ()
DarkRoastWithSteamedMilkAndMocha cost ()
HouseBlendWithSteamedMilk cost ()
DarkRoastWithSteamedMilk cost ()
DecafWithSteamedMilkAndMocha cost ()
DecafWithSteamedMilkAndMocha cost ()
ExpressoWithWhipandSoy cost ()
DarkRoastWithWhip cost ()
Each cost method computes the cost of the coffee along with other condiments in the order.
Can you say “Class Explosion” !!!!
Question
It is pretty obvious that Starbuzz has created a maintenance nightmare for themselves. What happens when the price of milk goes up? Or when they add a new caramel topping?
Beyond the maintenance problem -- what OO design principle(s) are they violating here?
Alternatives to the Design?Can’t we just use instance variables and inheritance in the superclass to keep track of the condiments?
New boolean values for each of the condiments
Now we implement the cost ( ) in Beverage (instead of keeping it abstract), so that it can calculate costs associated with the condiments for a particular beverage instance. Subclasses will still override the cost ( ), but they will also invoke the super version so that they can calculate the total cost of the basic beverage plus the cost of the added condiments.
Beverage description milk soy mocha whip
getDescription ( ) cost ( )
hasMilk ( ) setMilk ( ) hasSoy ( ) setSoy ( ) // and others
These get and set the boolean values for the condiments.
HouseBlend cost ( )
DarkRoast cost ( )
Decaf cost ( )
Expresso cost ( )
Is this ok?
What requirements or other factors might change that will impact this design?
1) Price changes for condiments will force us to alter the existing code2) New condiments will force us to add new methods and alter the cost method in the superclass.3) We may have new beverages. For some of these beverages the condiments may not be appropriate4) What if a customer wants a double mocha?
What else?
Meet the Decorator Pattern
We start with a beverage and “decorate” it with the condiments at runtime. If a customer wants a Dark Roast with Mocha and Whip we do the following:
1. Take a DarkRoast object
2. Decorate it with a Mocha object
3. Decorate it with a Whip object
4. Call the cost ( ) method and rely on delegation to add on the condiment costs.
How do you “decorate” and how does delegation come into this?
Constructing a drink order with Decorators1. Start with the DarkRoast object
2. Customer wants Mocha, so we create a Mocha object and wrap it around the DarkRoast.
3. The customer also wants Whip, so we create a Whip decorator and wrap Mocha with it.
cost ( )
DarkRoast inherits from Beverage and has a cost ( ) method that computes the cost of the drink.
cost ( ) cost ( )
The Mocha object is a “decorator”. Its type mirrors the object it is decorating, in this case, a Beverage. (“mirror” means it is the same type.
So Mocha has a cost ( ) method too, and through polymorphism we can treat any Beverage object wrapped in Mocha as a Beverage too. (Mocha is a subtype of Beverage)
cost ( ) cost ( ) cost ( )
Whip is a decorator, so it also mirrors DarkRoast’s type and includes a cost ( ) method.
So DarkRoast wrapped in Mocha and Whip is still a Beverage and we can do anything with it that we can do with a DarkRoast, including call its cost ( ) method.
Constructing a drink order with Decorators4. Now its time to compute the cost for the customer. Do this by calling
cost( ) on the outermost decorator, Whip, and Whip is going to delegate computing cost to the objects it decorates. Once it gets a cost, it will add on the cost of the Whip.
cost ( ) cost ( ) cost ( )
(1) First we call cost ( ) on the outermost decorator, Whip.
0.991.190.10$1.29
(2) Whip calls cost ( ) on Mocha
(3) Mocha calls cost ( ) on DarkRoast
(4) DarkRoast returns its cost, 99 cents
(5) Mocha adds its cost, 20 cents, to the result and returns the new total $1.19
(6) Whip adds its total, 10 cents, to the result from Mocha, and returns the final result -- $1.29.
So what do we know so far?
Decorators have the same supertype as the objects that they decorate.
You can use one or more decorators to wrap an object. Given that the decorator has the same supertype as the object it
decorates, we can pass around a decorated object in place of the original object.
The decorator adds its own behavior either before and/or after delegating to the object its decorates to do the job.
Objects can be decorated at any time, so we can decorate objects at runtime with as many decorators as we like.
Key point!
Decorator Pattern DefinedThe Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Component methodA ( ) methodB ( ) // other methods
ConcreteComponent
methodA ( )methodB ( )// other methods
Decorator
methodA ( ) methodB ( ) // other methods
ConcreteDecoratorA
Component wrappedObject
methodA ( ) methodB ( ) newBehavior ( ) // other methods
ConcreteDecoratorB
Component wrappedObject Object newState
methodA ( ) methodB ( ) // other methods
Each component can be used on its own or wrapped by a decorator component.
Each decorator HAS_A (wraps) a component, which means the decorator has an instance variable that holds a reference to a component.
Decorators implement the same interface or abstract class as the component they are going to decorate.
Decorators can extend the state of the component
The ConcreteDecorator has an instance variable for the thing it decorates (the Component the Decorator wraps)
Decorators can add new methods; however, new behavior is typically added by doing some computation before or after an existing method in the component
The ConcreteComponent is the object we are going to dynamically add new behavior to. It extends the Component.
Decorate the Beverages! Beverage
description getDescription ( ) cost ( ) // other methods
HouseBlend cost ( )
DarkRoast cost ( )
Expresso cost ( )
Decaf cost ( )
CondimentDecorator getDescription ( )
Milk Beverage beverage cost ( ) getDescription ( )
Mocha Beverage beverage cost ( ) getDescription ( )
Soy Beverage beverage cost ( ) getDescription ( )
Whip Beverage beverage cost ( ) getDescription ( )
Beverage acts as our abstract Component class
The four concrete components, one per coffee type.
The condiment decorators. Notice they need to implement the cost () as well as the getDescription ( ).
component
Some Real Code! public abstract class Beverage { String description = “Unknown Beverage”; public String getDescription ( ) { return description; } public abstract double cost ( );}
public abstract class CondimentDecorator extends Beverage { public abstract String getDescription ( ); }
Beverage is an abstract class with two methods getDescription ( ) and cost ( ).getDescription ( )is already implemented, but we need to implement cost ( ) in the subclasses.
First, we need to be interchangeable with Beverage, so we extend the Beverage class.
We are also going to require that the condiment decorators reimplement the getDescription ( ) method. We will see why in a sec…
Coding Beverages public class Expresso extends Beverage { public Expresso ( ) { description = “Expresso”; } public double cost ( ) { return 1.99; }}
public class HouseBlend extends Beverage { public HouseBlend ( ) { description = “HouseBlend”; } public double cost ( ) { return .89; } }
Coding Condiments public class Mocha extends CondimentDecorator { Beverage beverage; public Mocha(Beverage beverage) { this.beverage = beverage; } public String getDescription ( ) { return beverage.getDescription( ) + “, Mocha”; } public double cost ( ) { return .20 + beverage.cost ( ); }} We want our description to say not
only Dark Roast -- but to also include the item decorating each beverage for instance: Dark Roast, Mocha. So we first delegate to the object we are decorating to get its description, then append “, Mocha” to that description.
Similarly, to compute the cost of the beverage with Mocha, we first delegate to the object that is being decorated, so that we can compute its cost and then add in the cost of the Mocha.
Ordering Coffee public class StarbuzzCoffee { public static void main (String args[]) { Beverage beverage = new Espresso ( ); System.out.println ( beverage.getDescription ( ) + “ $ “ + beverage.cost ( )); Beverage beverage2 = new DarkRoast ( ); beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); beverage2 = new Whip (beverage2); System.out.println( beverage.getDescription ( ) + “$ “ + beverage2.cost ( )); }}
Real World Decorators
The java.io package uses the Decorator pattern!
InputStream
FileInputStream StringBufferInputStream ByteArrayInputStream FilterInputStream
BufferedInputStream
DataInputStream
LineNumberInputStream
PushbackInputStream
Heres the abstract component
FilterInputStream is an abstract decorator
These InputStreams are the ConcreteComponents. There are a few more that are not shown here.
Here are the concrete decorators.
The java.io Package (contd.) What is the typical set of objects that use decorators to add
functionality to reading data from a file?
100111101000010101010111
A Text File
FileInputStream is the component that’s being decorated. The Java I/O library supplies several components, including FileInputStream, StringBufferInputStream, and others. All of these give us the base component from which to read bytes.
BufferedInputStream is a concrete Decorator . BufferedInputStream adds behavior in two ways: it buffers input to improve performance, and also augments the interface with a new method readLine ( ) for reading character-based input, a line at a time.
LineNumberInputStream is also a concrete decorator. It adds the ability to count the line numbers as it reads data.
Exercise your brains…
How would you write a decorator that converts all uppercase characters to lowercase in the input stream?
Combining patterns: We have already seen a much better way of creating objects. How would you apply the Factory methods to create decorator objects?
Exercise your brain…
What would a good example of where Decorator patterns would be useful in your game?
Summary Decorator patterns are based on the open-closed principle!
– We should allow behavior to be extended without the need to modify existing code.
The Decorator Pattern – Provides an alternative to subclassing for extending behavior.– Involves a set of decorator classes that are used to wrap concrete
components– Decorator classes mirror the types of the components they decorate.– Decorators change the behavior of their components by adding new
functionality before and/or after method calls to the component.– You can wrap a component with any number of decorators.– Decorators are typically transparent to the client of the component -- unless
the client is relying on the component’s concrete type.– Decorators can result in many small objects in our design, and overuse can
be complex!
Factory Patterns
“Baking with OO Goodness”
Factory Patterns
Factory patterns are examples of creational patterns Creational patterns abstract the object instantiation
process. – Hide how objects are created– Make system independent of how its objects are created and
composed. Class creational patterns focus on the use of inheritance
to decide on the object to be instantiatedFactory method
Object creational patterns focus on the delegation of the instantiation to another objectAbstract Factory
“new” = “concrete”
Design Principle: “Don’t program to an implementation, program to an abstraction”
However, every time you do a “new” you need to deal with a “concrete” class, not an abstraction.Duck duck = new MallardDuck ( );
We want to use interfaces to keep code flexible
But we have to create an instance of a concrete class
With a whole set of related concrete classes:Duck duck; if (picnic) duck = new MallardDuck (); else if (hunting) duck = new DecoyDuck ( ); else if (inBathTub) duck = new RubberDuck ( );}
Whats wrong with this? What principle is broken here?
What can you do?
Principle: Identify the aspects that vary and separate them from what stays the same.
How might you take all the parts of your application that instantiate concrete classes and separate or encapsulate them from the rest of your application?
Identifying aspects that VaryOwn a pizza store in cutting edge Objectville!
Pizza orderPizza ( ) { Pizza pizza = new Pizza ( ); pizza.prepare () ; pizza.bake (); pizza.cut (); pizza.box (); return pizza;}
For flexibility it would be nice if this wasn’t concrete, but we can’t instantiate abstract classes!
Identifying Aspects that Vary (2/ But you need more than one type of pizza:Pizza orderPizza ( String type) { Pizza pizza; if (type.equals (“cheese”) { pizza = new CheesePizza (); } else if (type.equals(“greek”)) { pizza = new GreekPizza ( ); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza ( ); }
pizza.prepare () ; pizza.bake (); pizza.cut (); pizza.box (); return pizza;}
Instantiate based on type of pizza
Pass in the type of Pizza to orderPizza( )
Prepare the pizza
But the pressure is on to add more pizza types…. Need to add a couple trendy pizzas to their menu: Clam and
Veggie. Greek is not selling so well - so take it out!
What do you think would need to vary and what would stay constant?
Modified orderPizza ( )Pizza orderPizza ( String type) { Pizza pizza; if (type.equals (“cheese”) { pizza = new CheesePizza (); } else if (type.equals(“greek”)) { pizza = new GreekPizza ( ); } else if (type.equals(“veggie”)) { pizza = new VeggiePizza ( ); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza ( ); }
pizza.prepare () ; pizza.bake (); pizza.cut (); pizza.box (); return pizza;}
This is what varies
This is what we expect will stay the same
This code is not closed for modification!
Encapsulating Object Creation
Move the object creation out of the orderPizza ( ) method. How?
– Move the creation code into a special purpose object that is concerned with only creating pizzas
Pizza orderPizza ( String type) { Pizza pizza; pizza.prepare () ; pizza.bake (); pizza.cut (); pizza.box (); return pizza;}
if (type.equals (“cheese”) { pizza = new CheesePizza (); } else if (type.equals(“greek”)) { pizza = new GreekPizza ( ); } else if (type.equals(“veggie”)) { pizza = new VeggiePizza ( ); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza ( ); }
Pull it out
We place this code into a separate object SimplePizzaFactory
What’s going to go here?
Building a Simple Pizza Factory public class SimplePizzaFactory { public Pizza createPizza (String type ) { Pizza pizza = null;
if (type.equals (“cheese”) ) { pizza = new CheesePizza (); } else if (type.equals(“greek”)) { pizza = new GreekPizza ( ); } else if (type.equals(“veggie”)) { pizza = new VeggiePizza ( ); } else if (type.equals(“pepperoni”) { pizza = new PepperoniPizza ( ); }}
Code is still parameterized by the type of pizza, just like the original code.
Factories handle the details of the object creation.
Here’s code we plucked out of the orderPizza() method.
Could this method be made static?
Reworking the PizzaStore class public class PizzaStore { SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {this.factory = factory;
}public Pizza orderPizza (String type){
Pizza pizza;pizza = factory.createPizza (type);pizza.prepare () ;pizza.bake ();pizza.cut ();pizza.box ( );return pizza;
}}
New operator replaced by create method!
PizzaStore has a reference to the factory
PizzaStore gets the factory passed in the constructor
Why is this better?
SimplePizzaFactory may have many more clients than orderPizza ( ) method– PizzaShopMenu, HomeDelivery etc.
Client code does not have any concrete classes anymore!!
SimpleFactory is not really a design pattern but the actual Factory patterns are based on it!
SimpleFactory Pattern
PizzaStore SimplePizzaFactoryPizza
prepare( ) bake ( ) cut ( ) box ( )
CheesePizza
VegiePizza ClamPizza
PepperoniPizza
Client of the factory. Goes through factory to get instances of Pizza
This is the factory where we create pizzas; this should be the only part of our application that refers to concrete Pizza classes.
Product of the factory (abstract)
Concrete products. Each product needs to implement the Pizza interface.
Abstract class with some helpful implementations that can be overridden.
createPizza ()
createPizza ()
create method sometimes declared static.
Onwards with the Pizza Franchise
Franchises in different cities– Must ensure quality of pizza– Must account for regional differences (NY, Chicago..)
Want franchise store to leverage your PizzaStore code --> pizzas are prepared the same way
NY needs a factory that makes NY style pizza Chicago needs a factory that makes Chicago style pizza
One approach --> SimpleFactory
Applying SimpleFactory Pattern
NYPizzaFactory nyFactory = new NYPizzaFactory ( );
PizzaStore nyStore = new PizzaStore (nyFactory); nystore.order (“Veggie”);
ChicagoPizzaFactory CFactory = new ChicagoPizzaFactory ( ); PizzaStore CStore = new PizzaStore (CFactory); Cstore.order (“Veggie”);
Issues:• Franchises using your factory to create pizza, but using homegrown procedures for baking etc.• Yet, each franchise “needs room for adding own improvements”
•You don’t want to know what they put on their pizza - detail that should be “exposed” only to the individual stores. Yet you want to have some control (quality control!)
What is needed is a framework that ties the store and pizza creation together, yet allows for flexibility.
Here we create a factory for making NY style pizza
Then we create a PizzaStore and pass it a reference to the NY factory
…and when we make pizzas we get NY style pizzas
Need a mechanism to “localize” all pizza making activities to the PizzaStore class and yet give franchises freedom to have their own regional style!
A Framework
public abstract class PizzaStore { public Pizza orderPizza (String type) { Pizza pizza; pizza = createPizza (type);
pizza.prepare ( ); pizza.bake ( ); pizza.cut ( ); pizza.box ( );
return pizza; }
abstract createPizza (String type); }
Now createPizza is back to being a call to a method in the PizzaStore rather than a Factory object!
All this is the same. Break out into orderPizza ( ) method.
Our factory method is now abstract in PizzaStore.
Allows each individual subclass to decide which Factory to invoke.All subclasses MUST implement the createPizza method.
Allowing the subclasses to decide…PizzaStore
createPizza( ) orderPizza ( )
NYStylePizzaStore
createPizza( )
ChicagoStylePizzaStore
createPizza( )
Each subclass overrides the createPizza ( ) method, while all subclasses make use of the orderPizza () method defined in the PizzaStore.
If franchise wants NY style pizzas for its customers, it uses the NY subclass, which has its own createPizza ( ) method, creating NY style pizzas.
public Pizza createPizza (type) { if (type.equals(“cheese”)) pizza = new NYStyleCheesePizza ( ); else if (type.equals (“pepperoni”)) pizza = new NYStylePepperoniPizza ( ); }
createPizza () returns a Pizza and the subclass is fully responsible for which concrete Pizza it instantiates
Here’s where the concrete classes are being created!
Note: orderPizza ( ) method in superclass has no clue which Pizza we are creating. It only knows it can prepare, bake, cut and box it!
A Factory Method Up Close!
A “Factory” method handles object creation and encapsulates it in a subclass. This decouples the client code in the superclass from the object creation code in the subclass.
abstract Product factoryMethod (String type)
A factory method is abstract so the subclasses are counted on to handle object creation.
A factory method returns a Product that is typically used within methods defined in the superclass.
A factory method isolates the client (the code in the superclass, like orderPizza ( )) from knowing what kind of concrete Product is actually created.
A factory method may or may not be parameterized to select among several variations of a product.
Factory Method Pattern
All factory patterns encapsulate “object creation” Factory method pattern encapsulates object creation by letting
subclasses decide what objects to create. Who are the players in this pattern?
The Players!
The Product Classes The Creator Classes
Notice the parallel class hierarchies: both have abstract classes that are extended by concrete classes, which know about specific implementations for NY and Chicago.
Pizza
NYStyleCheesePizzaNYStylePepperoniPizza
NYStyleClamPizzaNYStyleVeggiePizza
CStyleCheesePizzaCStylePepperoniPizza
CStyleClamPizzaCStyleVeggiePizza
PizzaStore
NYPizzaStore
ChPizzaStore
Factory method is key to encapsulating this knowledge!
NYPizzaStore & CPizzaStore encapsulate all the knowledge about how to make NY Style Pizzas and Chicago Style Pizzas respectively.
Factory Method Pattern Defined
All products must implement the same interface so that the classes which use the products can refer to the interface, not the concrete class.
The ConcreteCreator is responsible for creating one or more concrete products. It is the only class that has knowledge of how to create these products.
The ConcreteCreator implements the factoryMethod ( ), which is the method that actually produces the products.
The abstract factoryMethod ( )is what all Creator subclasses must implement.
The Creator is the class that contains the implementations for all the methods to manipulate the products, except for the factory method!
The Factory Method Pattern defines an interface for creating an object but lets the subclasses decide which class instantiate. Factory method lets a class defer instantiation to subclasses.
Why decides?
Meanwhile, back at the PizzaStore….
Things are going good, but you have learned that a few franchises are substituting inferior ingredients -> bringing down the Objectville name!
How are you going to ensure each factory is using quality ingredients? – You are going to build a factory that produces them and ships
them to your franchises!– One problem: franchises are located in different regions so what
is red sauce in NY is not red sauce in Chicago! So: same product families (dough, cheese, sauce etc.) but
different implementations based on region.
Building the Ingredient Factory Ingredient factory: creates each ingredient in the ingredient family (but does
not handle regional differences yet!)
public Interface PizzaIngredientFactory { public Dough createDough ( ); public Sauce createSauce ( ); public Cheese createCheese ( ); public Veggies [ ] createVeggies ( ); public Pepperoni createPepperoni ( ); public Clams createClams ( ); }
For each ingredient we define a create method in our interface.
Lots of new classes here, one per ingredient
If we had some common “machinery” to implement in each instance of factory, we could have made this abstract instead.
What to do next?1. Build a factory for each region. To do this, create a subclass of PizzaIngredientFactory
that implements each create method.2. Implement a set of ingredient classes to be used with the factory, like RedPeppers,
ThickCrustDough, etc. These classes can be shared among regions where appropriate.3. Then we still need to hook all this up by working our new ingredient factories into the old
PizzaStore code.
(1) The New York Ingredient Factory
public class NYPizzaIngredientFactory implements PizzaIngredientFactory { public Dough createDough ( ){ return new ThinCrustDough ( ); } public Sauce createSauce ( ){ return new MarinaraSauce ( ); } public Cheese createCheese ( ) { return new ReggianoCheese ( ); } public Veggies [ ] createVeggies ( ){ Veggies veggies[ ] = { new Garlic ( ), new Onion ( ), new Mushroom ( )}; return veggies; } // other ingredients }
The NY ingredient factory implements the interface for all ingredient factories
For each ingredient in the ingredient family, we create the NY version.
Reworking the Pizzas public abstract class Pizza { String name;
Dough dough;Sauce sauce;Veggies veggies[];Cheese cheese;Pepperoni pepper;Clams clams;
abstract void prepare ( );void bake ( ) {
System.out.println ( “Bake for 25 minutes at 350”);}
void cut ( ) { }void box ( ) { }void setName (String name) { this.name = name;}String getName ( ) { return name; }}
}
Each pizza holds a set of ingredients that are used in its prep.
The prepare () method is abstract. This is where we are going to collect the ingredients needed for the pizza which will come from the ingredient factory.
Other methods remain the same
Reworking the Pizzas (contd.) public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza ( PizzaIngredientFactory ingredientFactory) {this.ingredientFactory = ingredientFactory;
}
void prepare ( ){System.out.println (“Preparing: “ + name );dough = ingredientFactory.createDough ( );sauce = ingredientFactory.createSauce ( );cheese = ingredientFactory.createCheese ( );
}}
Here’s where the magic happens!
To make a pizza now, we need a factory to provide the ingredients. So each class gets a factory passed into its constructor, and its stored in an instance variable.
The prepare ( ) method steps through the creating a cheese pizza, and each time it needs an ingredient, it asks the factory to produce it.
Code Up Close!
sauce = ingredientFactory.createSauce ( );
We are setting the pizza instance variable to refer to the specific sauce used in this pizza
This is the ingredient Factory. The pizza does not care which factory is used, as long as it is an ingredient factory.
The createSauce () method returns the sauce that is used in its region. If this is NY ingredient factory, then we get marinara sauce.
Revisiting the Pizza Store public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza (String item) { Pizza pizza = null; PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory ( );
if (item.equals(“cheese”)){pizza = new CheesePizza (ingredientFactory);pizza.setName(“New York Style Cheese Pizza”);
} else if (item.equals(“veggie”)){pizza = new VeggiePizza (ingredientFactory);pizza.setName (“New York Style Veggie Pizza”);
} // same for all other pizza types. return pizza; }}
The NY Store is composed with a NY pizza ingredient factory. This will be used to produce the ingredients for all NY style pizzas.
We now pass each pizza the factory that should be used to produce its ingredients.
For each type of pizza we instantiate a new Pizza and give it the factory that it needs to get its ingredients.
What have we done? We provided a means of creating a
family of ingredients for pizzas by introducing a new type of factory called -- Abstract Factory.
Abstract Factory:– Gives an interface for creating a
family of products.– By writing code that uses this
interface we decouple our code from the actual factory that creates the products.
– Allows us to implements a variety of factories that produce products meant for different contexts.
– Decoupling --> enables substitution of different factories to get different behaviors.
Defines the interface
Objectville Abstract IngredientFactory
NY Chicago
Provides implementations for products
Pizza Store
Pizza made with ingredients produced by the concrete factory
The Abstract Factory Pattern
The AbstractFactory defines the interface that all Concrete factories must implement, which consists of a set of methods for producing products.
The concrete factories implement the different product families. To create a product, the client uses one of these factories, so it never has to instantiate a product object.
This is the product family. Each concrete factory can produce an entire set of objects.
The client is written against the abstract factory and then composed at runtime with an actual factory.
The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
Summary All factories encapsulate object creation Simple factory, while not a bona fide design pattern, is a simple way to decouple
your clients from concrete classes. Factory method relies on inheritance: object creation is delegated to subclasses
which implement the factory method to create objects Abstract Factory relies on object composition: object creation is implemented in
methods exposed in the factory interface. All factory methods promote loose coupling by reducing the dependency of your
application on concrete classes. The intent of Factory method is to allow a class to defer instantiation to its
subclasses. The intent of the Abstract Factory is to create families of related objects without
having to depend on their concrete classes. The Dependency Inversion principle guides us to avoid dependencies on concrete
types and to strive for abstractions. Factories are a powerful technique for coding to abstractions, not concrete classes.
The Singleton Pattern
“One of a Kind Objects”
What is this?
Singleton: How to instantiate just one object - one and only one! Why?
– Many objects we need only one of: thread pools, caches, dialog boxes, objects that handle preferences and registry settings etc.
– If more than one instantiated: • Incorrect program behavior, overuse of resources, inconsistent results
Alternatives:– Use a global variable
• Downside: assign an object to a global variable then that object might be created when application begins. If application never ends up using it and object is resource intensive --> waste!
– Use a static variable• Downside: how do you prevent creation of more than one class object?
The Little SingletonHow would you create a single object?
And what if another object wanted to create a MyObject? Could it call new on MyObject again?
Can we always instantiate a class one or more times?
And if not?
Is this possible?
public MyClass { private MyClass ( ) { } }
What does it mean?
new MyObject ( );
Yes.
Yes. Caveat: Only if it is public class
Only classes in the same package can instantiate it - but they can instantiate it more than once.
Yes. It is a legal definition
A class that can’t be instantiated because it has a private constructor
The Little Singleton (contd.)
Is there any class that could use a private constructor? What’s the meaning of the following?
Instantiating a class with a private constructor:
public MyClass { public static MyClass getInstance ( ) { } }
public MyClass { private MyClass ( ) { } public static MyClass getInstance ( ) { } }
The Classic Singleton Pattern public class Singleton { private static Singleton uniqueInstance; // other useful instance variables
private Singleton ( ) { } public static Singleton getInstance ( ) { if (uniqueInstance == null) { uniqueInstance = new Singleton
( ); } return uniqueInstance; }
// other useful methods }
We have a static variable to hold our one instance of the class Singleton.
Constructor is declared private; only singleton can instantiate this class!
The getInstance ( ) method gives us a way to instantiate the class and also return an instance of it.
Of course, Singleton is a regular class so it has other useful instances and methods.
Code Up Close
if (uniqueInstance == null) { uniqueInstance = new Singleton ( ); } return uniqueInstance;
uniqueInstance holds our ONE instance; remember it is a static variable
If uniqueInstance is null, then we haven’t created the instance yet…
…and if it doesn’t exist, we instantiate Singleton through its private constructor and assign it to the uniqueInstance. Note that if we never need the uniqueInstance, it never gets created -->
lazy instantiation.
If uniqueInstance wasn’t null, then it was previously created. We just fall through to the return statement. In either case, we have an instance and we return it.
Singleton Pattern DefinedThe Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.
Singleton
static uniqueInstance // other useful variables
static getInstance ( ) // other methods
The getInstance ( ) method is static, which means it is a class method, so you can conveniently access this method anywhere in your code using Singleton.getInstance ( ). That’s just as easy as accessing a global variable, but we get benefits like lazy instantiation from the Singleton.
The uniqueInstance class variable holds our one and only one instance of Singleton.
A class implementing a Singleton Pattern is more than a Singleton; it is a general purpose class with its own set of data and methods.
Houston, we have a problem….
We improved the Chocolate Boiler code with the Singleton pattern and we added some optimizations to the Chocolate Boiler Controller that makes use of multiple threads
Ugh… the Chocolate Boiler’s fill ( ) method was able to start filling the boiler even though a batch of milk and chocolate was already boiling! That’s 500 gallons of milk and chocolate spilled.
Could the addition of threads have caused this?
Hershey, PA
Be the JVM
We have two threads each executing this code: Chocolate Boiler boiler = ChocolateBoiler.getInstance ( ); fill ( ); boil ( ); drain ( );
Could the two threads get hold of different boiler objects?
public static ChocolateBoiler getInstance ( ){ if (uniqueInstance == null){ uniqueInstance = new ChocolateBoiler ( ); } return uniqueInstance; }
Dealing with Multi-threading
Easy fix: make getInstance ( ) a synchronized method
public class Singleton { private static Singleton uniqueInstance; // other useful instance variables
private Singleton ( ) { } public static synchronized Singleton getInstance ( ) { if (uniqueInstance == null) { uniqueInstance = new Singleton ( ); } return uniqueInstance; }
// other useful methods }
By adding the synchronized keyword to getInstance ( ) method, we force every thread to wait its turn before it can enter the method. That is, no two threads may enter the method at the same time.
This fixes the problem, but synchronization is expensive; is this really an issue? -- synchronization is really only needed the first time through this method. Once we have created the first Singleton instance, we have no further need to synchronize this method. So after the first time, synchronization is totally unneeded overhead.
public class Singleton { private static Singleton uniqueInstance = new Singleton ( );
private Singleton ( ) { } public static Singleton getInstance ( ) { return uniqueInstance; }}
Can we improve multithreading?
1. Do nothing if the performance of getInstance ( ) isn’t critical to your application. [ remember that synchronizing can decrease performance by a factor of 100]
2. Move to an eagerly created instance rather than a lazily created one.
Go ahead and create an instance of Singleton in a static initializer. This code is guaranteed to be thread safe!
We’ve already got an instance, so just return it.
Can we improve multithreading?3. Use “double-locking” to reduce the use of synchronization in
getInstance ()
• First check to see is instance is created, THEN synchronize. public class Singleton { private volatile static Singleton uniqueInstance; // other useful instance variables
private Singleton ( ) { } public static Singleton getInstance ( ) { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null ){ uniqueInstance = new Singleton ( ); } } } return uniqueInstance; } }
Check for an instance and if there isn’t one, enter the synchronized block.
Note we only synchronize the first time through.
Once in the block, check again if null. If so create instance.
The volatile keyword ensures that multiple threads handle uniqueInstance variable correctly when it is being initialized to the Singleton instance.Only JDK 1.5!
If performance is an issue then this method can drastically reduce overhead!
Summary The Singleton Pattern ensures you have at most one instance of a class in your
application The Singleton Pattern also provides a global access point to that instance. Java’s implementation of the Singleton Pattern makes use of a private
constructor, a static method combined with a static variable Examine your performance and resource constraints and carefully choose an
appropriate Singleton implementation for multi-threaded applications. Beware of double-checked locking implementation -- it is not thread-safe pre
JDK 1.5 Be careful if you are using multiple class loaders -- this can defeat the purpose
of the Singleton implementation If you are using a JVM earlier than 1.2, you’ll need to create a registry of
Singletons to defeat the garbage collector.
The Command Pattern
Encapsulating Invocation
Command Pattern
Encapsulates method invocation - Purpose:
– crystallize pieces of computation so that the objects invoking the computation do not have to worry about how to do things - they just use the crystallized method!
– Can also do some “wickedly smart” things with these encapsulated methods like save them for logging or reuse them to implement “undo”
A Motivating Example
Goal: Program a Remote Control that can be used to control the devices in the house
Requirements:– Remote control features seven programmable slots– Each slot can be assigned to a different household device– Each slot has a corresponding on/off button– Remote has a global undo button that undoes the last button
pressed.– A set of vendors classes are provided to give you an idea of
the interfaces of the objects that need to be controlled from the remote.
A Pictorial View
on Off
Seven slots to programEach slot contains a different device and is controlled via the buttons.
On and off buttons for each of the seven slots
These two control device 1
Global “undo” button
CeilingLight on ( ) off ( ) dim ( )
TV on ( ) off ( ) setInputChannel ( ) setVolume ( )
FaucetControl openValue ( ) closeValue ( )
Thermostat setTemperature ( )
Hottub circulate ( ) jetsOn ( ) jetsOff ( ) setTemperature ( )
Vendor Classes
Observations, anyone? Expectation: see a bunch of classes with on ( ) and off ( ) methods -->
common interface Instead: each vendor class has its own API: dim ( ), setTemperature ( ),
setVolume ( ), setDirection ( ) Observation:
– Separation of concerns: remote should know how to interpret button presses and make requests, but it really should not know anything about home automation or how to turn on a hot tub.
– Any issues?
Requirement: There will be more vendor classes in the future - design must accommodate for that
If the remote is dumb, how do we design a remote so that it can invoke an action - turn on a light?
Enter -- The Command Pattern! Command Pattern allows you to decouple the requester of an
action from the object that actually performs the action– Requester == remote control, Object == vendor classes
How does it work?– Introduce “command objects” into your design. A command object
encapsulates a request to do something (like turn on a light) on a specific object (say, the living room light).
– Every time a remote button is pressed, its corresponding command object goes to work!
– Remote does not have any idea what the work is, it just has a command object that knows how to talk to the right object to get the work done.
– Here the remote is decoupled from the object!
A Diner Example - A Brief Introduction to the Command Pattern
(1) You, the Customer give the Waitress your Order
Order
(2) The Waitress takes the Order, places it on the order counter and says “Order up!”
(3) The Short-Order Cook prepares your meal from the Order.
Ordering in Objectville
The customer knows what he/she wants and creates an order
order
takeOrder ( )
createOrder ( )
The Waitress takes the Order, and when she gets around to it, she calls its orderUp ( ) method to begin the Order’s preparation.
order
The Order has all the instructions needed to prepare the meal. The Order directs the Short Order Cook with methods like makeBurger ( ).
The Short Order Cook follows the instructions of the Order and produces the meal.
Start Here
The Objectville Diner Objects and Responsibilities
Order Slip: encapsulates a request to prepare a meal Waitress: take the Order Slips and invoke the
orderUp ( ) method on them The Short Order Cook: has the knowledge required
to prepare the meal!
From the Diner to the Command Pattern
create Command object ( )
The client is responsible for creating the command object. The command object consists of a set of actions on a receiver
public void execute { receiver.action1 (); receiver.action2 (); }
action1( ) action2( )
The actions and the Receiver are bound together in the command object.
The Command Object provides one method, execute ( ), that encapsulates the actions and can be called to invoke the actions on the Receiver.
execute ( )
(1) createCommandObject ( )
(2) setCommand ( )
The client calls setCommand ( ) on an Invoker object and passes it the command object, where it gets stored until it is needed.
setCommand ( )
execute ( )At some point in the future the Invoker calls the Command object’s execute () method.
execute ( )
action1 ( ) action2 ( ) action1 () , action2 ( )
…which results in the actions being invoked on the Receiver
(3) Loading the Invoker(1) The client creates a
command object.(2) The client does a
setCommand ( ) to store the command object in the invoker.
(3) Later… the client asks the invoker to execute the command . Note: once the command is loaded into the invoker, it may be used and discarded or it may remain and be used many times.
Start here
Coding Our First Command Object (1/3)
Implementing the Command Interface: public interface Command { public void execute ( ); }
Implementing a Command to turn the light on public class LightOnCommand implements Command { Light light; public LightOnCommand (Light light) { this.light = light; } public void execute ( ) { light.on ( ); } }
Simple. All we need is one method called execute ( ).
This is a command, so we need to implement the Command interface.
The constructor is passed the specific light that this command is going to control - say the living room light - and stashes it in the light instance variable. When execute ( ) gets called, this is the light object that is going to be the Receiver of the request.
The execute method calls the on ( ) method on the receiving object, which is the light that we are controlling.
Coding the First Command Object (2/3)
Using the Command Object public class SimpleRemoteControl {
Command slot; public SimpleRemoteControl ( ) { } public void setCommand (Command command) { slot = command; } public void buttonWasPressed ( ) { slot.execute ( ); } }
We have one slot to hold our command, which will control one device.
We have a method for setting the command the slot it’s going to control. This could be called multiple times if the client of this code wanted to change the behavior of the remote button.
This method is called when the button is pressed. All we do is take the current command bound to the slot and call its execute ( ) method.
Coding the First Command Object (3/3)
Creating a Simple test to use the Remote Control
public class RemoteControlTest {
public static void main (String [] args) { SimpleRemoteControl remote = new SimpleRemoteControl ( ); Light light = new Light ( ); LightOnCommand lightOn = new LightOnCommand (light);
remote.setCommand (lightOn);
remote.buttonWasPressed ( ); }}
This is our client in Command Pattern-speak
The remote is our Invoker; it will be passed a command object that can be used to make requests.
Now we create a Light Object - this will be the Receiver of the request.
Here, create a command and pass it to the Receiver.Here pass the
command to the Invoker.
Then, we simulate the button being pressed.
The Command Pattern DefinedThe Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
execute ( ) { receiver.action ( ); }
action ()An encapsulated request
Command object encapsulates a request by binding together a set of actions on a specific receiver.To achieve this it packages the actions and the receiver up into an object that exposes just one method execute ( ).From the outside no other objects really know what actions get performed on what receiver. They just call the execute () to service their request!
The Command Pattern DefinedThe Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
execute ( ) { receiver.action ( ); }
action ()An encapsulated request
We’ve seen a couple of examples of parameterizing an object with a command.The Waitress was parameterized with multiple orders throughout the day.In the simple remote control we can first load the button slot with a light on command and then later replace it with a open the garage door command.
The Command Pattern DefinedThe Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
execute ( ) { receiver.action ( ); }
action ()An encapsulated request
Client Invoker
setCommand ( )
public void execute ( ) { receiver.action ( ) }
public void execute ( ) { receiver.action ( ) }
<< Interface >> Command execute ( ) undo ( )
Receiver action ( )
Concrete Command execute () undo ( )
Command declares an interface for all commands
Invoker holds a command and at some point asks the command to carry out a request by calling its execute ( ) method.
The client is responsible for creating a ConcreteCommand and setting its Receiver.
The Receiver knows how to perform the work needed to carry out any request. Any class can act as a Receiver.
Concrete Command defines a binding between an action and a Receiver. The Invoker makes a request by calling execute ( ) and the ConcreteCommand carries it out by calling one or more actions on the Receiver.
The execute method invokes the action(s) on the Receiver needed to fulfill request.
Implementing the RemoteControlpublic class RemoteControl { Command[] onCommands; Command[] offCommands; public RemoteControl() { onCommands = new Command[7]; offCommands = new Command[7]; Command noCommand = new NoCommand(); for (int i = 0; i < 7; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } } public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonWasPushed(int slot) { onCommands[slot].execute(); } public void offButtonWasPushed(int slot) { offCommands[slot].execute(); } public String toString() { // code here }
This time around the remote is going to handle seven On and Off Commands which we will hold in the corresponding array.
In the constructor all we need to do is instantiate the on and off arrays.
The setCommand() method takes a slot position and an On and Off command to be stored in that slot. It puts these commands in the On and Off array for later use.
When an On or a Off button is pressed, the hardware takes care of calling the corresponding methods OnButtonWasPushed ( ) or OffButtonWasPushed ( ).
Used for testing.
Implementing the Commandspublic class LightOffCommand implements
Command { Light light; public LightOffCommand(Light light) { this.light = light; } public void execute() { light.off(); }}
public class StereoOnWithCDCommand implements Command {
Stereo stereo; public StereoOnWithCDCommand(Stereo
stereo) { this.stereo = stereo; } public void execute() { stereo.on(); stereo.setCD(); stereo.setVolume(11); }}
The LightOffCommand works exactly like the LightOnCommand, except that we are binding the receiver to a different action: the off() command.
An instance of the stereo we are going to control is passed to constructor.
To carry out this request we need to call three methods on the stereo: first, turn it on, then set it to play the CD, and finally set the volume to 11 !
Testing the Codepublic class RemoteLoader { public static void main(String[] args) { RemoteControl remoteControl = new RemoteControl(); Light livingRoomLight = new Light("Living Room"); LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight); LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0);}
Create all the devices
Create all the Command objects
Load the command objects
Ready to roll! Test out the remote!
What is the NoCommand? In the remote control, we didn’t want to check to see if a
command was loaded for every slot. To do this we would need to do:
public void onButtonWasPushed (int slot) { if (onCommands[slot] != null ){ onCommands[slot].execute ( ); } }
To get around it, we introduce a new “NoCommand” object public class NoCommand implements Command { public void execute ( ) { }; }
Fixing the RemoteControl constructor: Command noCommand = new NoCommand ( ); for (int j=0; I < 7; j++ ){ onCommands[I] = noCommand; off Commands[I] = noCommand; }
NoCommand is an example of a null object. A null object is useful when you don’t have a meaningful object to return, yet you want to remove the responsibility for handling null from the client.
NoCommand is an example of a null object. A null object is useful when you don’t have a meaningful object to return, yet you want to remove the responsibility for handling null from the client.
Adding the Undo Feature
1. When commands support undo, they have an undo ( ) method that mirrors the execute ( ) method. Whatever execute ( ) last did, undo ( ) reverses it.
public interface Command { public void execute ( ); public void undo (); }
2. Implement the undo method in the LightOnCommand public class LightOnCommand implements Command {
public LightOnCommand (Light light){
this.light = light; } public void execute ( ) { light.on ( ); } public void undo ( ) { light.off ( ); } }
execute ( ) turns the light on so undo turns it off. Reverse for LightOffCommand.
Updating the RemoteControl class3. To add support for the undo button we only have to make a few small changes to
RemoteControl class
public class RemoteControl { Command[] onCommands; Command[] offCommands; Command undoCommand; public RemoteControl() { onCommands = new Command[7]; offCommands = new Command[7]; Command noCommand = new NoCommand(); for (int i = 0; i < 7; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } undoCommand = noCommand; }
This is where we will stash the last command executed for the undo button
Just like the other slots this is initialized to a NoCommand.
RemoteControl Classpublic void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } public void onButtonWasPushed(int slot) { onCommands[slot].execute(); undoCommand = onCommands[slot]; } public void offButtonWasPushed(int slot) { offCommands[slot].execute(); undoCommand = onCommands[slot]; }
public void undoButtonWasPushed ( ) { undoCommand.undo ( ); } public String toString() { // code here }}
When the button is pressed we take the command and first execute it; then we save a reference to it in the undoCommand instance variable. We do this for both “on” and “off” commands.
When the undo button is pressed, we invoke the undo ( ) method of the command stored in the undoCommand. This reverses the operation that was last executed.
Using State to Implement Undopublic class CeilingFan { public static final int HIGH = 3; public static final int MEDIUM = 2; public static final int LOW = 1; public static final int OFF = 0; String location; int speed; public CeilingFan(String location) { this.location = location; speed = OFF; } public void high() { speed = HIGH; System.out.println(location + " ceiling fan is on high"); } public void medium() { speed = MEDIUM; System.out.println(location + " ceiling fan is on medium"); } public void low() { speed = LOW; System.out.println(location + " ceiling fan is on low"); }
public void off() { speed = OFF; System.out.println(location + " ceiling fan is off"); }
public int getSpeed() { return speed; } }
Holds local state
Set the speed of the ceiling fan.
Can get the current speed.
Adding Undo to Ceiling Fan Commandspublic class CeilingFanHighCommand implements Command { CeilingFan ceilingFan; int prevSpeed; public CeilingFanHighCommand(CeilingFan ceilingFan) { this.ceilingFan = ceilingFan; } public void execute() { prevSpeed = ceilingFan.getSpeed(); ceilingFan.high(); } public void undo() { if (prevSpeed == CeilingFan.HIGH) { ceilingFan.high(); } else if (prevSpeed == CeilingFan.MEDIUM) { ceilingFan.medium(); } else if (prevSpeed == CeilingFan.LOW) { ceilingFan.low(); } else if (prevSpeed == CeilingFan.OFF) { ceilingFan.off(); } }}
Added local state to keep track of the previous speed of the fan.
In execute ( ), before we change the speed we need to first record its previous state, just in case we need to undo our actions.
To undo, we set the speed of the fan back to its previous state.
The Party Mode
Executing multiple commands with one– Push one button to dim the lights, turn on the stereo and the
TV and set the to DVD. public class MacroCommand implements Command { Command[] commands; public MacroCommand (Command[ ] commands){ this.commands = commands; } public void execute ( ) { for (int j = 0; j < commands.length; j++){ commands[I].execute ( ); } }}
Take an array of Commands and store them in the MacroCommand
When the macro gets executed by the remote, execute those commands one at a time.
Using the Macro Command
1. Create the set of commands we want to go into the macro.
2. Create two arrays, one for the On Commands and the other for the Off Commands and load them with the corresponding commands.
3. Assign the macroCommand to the button as before.
4. Then push some buttons to test it out!
More Uses of the Command Pattern - Queuing Requests Commands provide a nice mechanism to package a piece of
computation (a receiver and a set of actions) and pass it around as a first-class object.
Imagine a job queue: – Add commands to the queue on one end, and on the other end sits a group of
threads– Threads run the following script:
• Remove command from the queue• Call its execute method• Wait for the call to finish• Discard the command object and retrieve the new one.
Here job queues are totally decoupled from the objects that are doing the computation - one minute the thread may be doing a financial computation and the next retrieving something from the network.
More Uses: Logging Requests
Semantics of some applications require that we log all actions and be able to recover after a crash by re-invoking those actions. The Command Pattern can store these semantics with the addition of two new methods: store ( ) and load ( ). – In Java we could use serialization to implement this.
How does it work?– As we execute commands, we store a history of them on disk
– When a crash occurs, we reload the command objects and invoke their execute () methods in batch and in order.
Summary
The Command pattern decouples an object making a request from one that knows how to perform it.
A Command object is at the center of this decoupling and encapsulates a receiver with an action (or set of actions)
An invoker makes a request of a Command object by calling its execute () method, which invokes those actions on the receiver.
Invokers can be parameterized with the Commands, even dynamically at runtime.
Commands may support undo by implementing an undo method that restores the object to its previous state before the execute ( ) method was last called.
Macro commands are a simple extension of Command that allow multiple commands to be invoked.
Commands may also be used to implement logging and transactional systems.
The Adapter Pattern
Putting a Square Peg in a Round Hole!
Wrapping Objects to Unify Interfaces
Question: What pattern wraps objects to give them new functionality?
Now we wrap objects with a different purpose:– To make their interfaces look like something they are not
– To simplify the interfaces of objects
Adapters
Real world is full of them!– Some examples?
Object oriented adapters– Scenario: you have an existing software system that you need to work a
new vendor library into, but the new vendor designed their interfaces differently than the last vendor.
– What to do? Write a class that adapts the new vendor interface into the one you’re expecting.
Your Existing System
Vendor Class
Their interface doesn’t match the one you’ve written your code against. Not going to work!
Your Existing System
Vendor Class
Adapter
The adapter implements the interface your classes expect
And talks to the vendor interface to service your requests
== Your Existing System
Vendor Class
Adapter
No code changes New code No code changes
If it walks like a duck…..
If it walks like a duck and quacks like a duck, then it might be a duck turkey wrapped with a duck adapter….
public interface Duck { public void quack (); public void fly (); } public class MallardDuck implements Duck { public void quack () { System.out.println(“Quack”); } public void fly ( ) { System.out.println (“I am flying”); } }
Meet the fowl!
public interface Turkey {
public void gobble (); public void fly ( ); } public class WildTurkey implements Turkey { public void gobble ( ) { System.out.println(“Gobble Gobble”); } public void fly ( ){ System.out.println(“I’m flying a short distance”); } }
Concrete implementations are similar -- just print out the actions.
Now….
Lets say you are short on Duck objects and would like to use some Turkey objects in their place.– Can’t use them outright because they have a different interface.
public class TurkeyAdapter implements Duck { Turkey turkey;
public TurkeyAdapter (Turkey turkey) {this.turkey = turkey;
}public void quack ( ) {
turkey.gobble ( );}public void fly ( ){
for (int j = 0; j<5; j++) turkey.fly ( );
} }}
First, you need to implement the interface of the type you are adapting to. This is the interface your client expects.
Next, we need to get a reference to the object that we are adapting; here we do that through the constructor.
Now we need to implement all the methods in the interface; the quack() translation between classes is easy; just call the gobble method.
Even though both interfaces have a fly ( ) method, Turkeys fly in short spurts -- they can’t do long distance flying like ducks. To map between a Duck’s fly ( ) method and a Turkey’s we need to call the Turkey’s fly ( ) method five times to make up for it.
The Adapter Pattern DefinedThe Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
Client <<Interface>> Target request ( )
Adapter request ( )
Adaptee specificRequest ()
The client sees only the Target interface.
The Adapter implements the target interface
All requests get delegated to the AdapteeAdapter is composed with the Adaptee
Full of good OO design principles:--Use of object composition--Pattern binds the client to an interface and not an implementation
Full of good OO design principles:--Use of object composition--Pattern binds the client to an interface and not an implementation
Object and Class Adapters There are two types of Adapters
– Object Adapter : what we have seen so far.
– Class Adapter: not as common as it uses multiple inheritance, which isn’t possible in Java.
Client <<Interface>> Target request ( )
Adapter request ( )
Adaptee specificRequest ()
Difference: The only difference is that with class adapter we subclass the Target and the Adaptee, while the object adapter uses composition to pass requests to an adaptee.
Question: Object Adapters and Class Adapters use two different means of adapting the adaptee (composition versus inheritance). How do these implementations affect the flexibility of the adapter?
Real World Adapters Old world Enumerators
New world Iterators
And today…legacy code that exposes the Enumerator interface. Yet we want new code to use Iterators. Need an adapter.
<<interface>> Enumeration hasMoreElements ( ) nextElement ( )
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
Enumeration has a simple interface.
Tells whether there are any more elements in the collection.
Returns the next element
Tells you if you have looked at all the elements
Gets the next one
Removes an item from the collection
Adapting an Enumeration to an Iterator First step: examine the two interfaces
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
<<interface>> Enumeration hasMoreElements ( ) nextElement ( )
Target interfaceThese two methods look easy, they map straight to hasNext ( ) and next ( ) in Iterator
Adaptee interfaceBut what about this method remove ( ) in Iterator? There’s nothing like that in Enumeration.
Designing the Adapter
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
EnumerationIterator hasNext ( ) next ( ) remove ( )
<<interface>> Enumeration hasMoreElements () nextElement ()
Your new code gets to use Iterators, even if there’s really an Enumeration underneath.
EnumerationIterator is the Adapter
We are making the Enumerations in your old code look like Iterators for your new code.
A class implementing the Enumeration interface is the adaptee.
Dealing with the remove ( ) method
Enumeration is a “read only” interface - it does not support the remove ( ) method.– Implies there is no real way to implement a fully functioning
remove () method.
– The best that can be done is to throw a runtime exception.
– Iterator designers foresaw the need and have implemented an UnsupportedOperationException.
Here the adapter is not perfect but is a reasonable solution as long as the client is careful and the adapter is well-documented.
EnumerationIterator - The Code public class EnumerationIterator implements Iterator { Enumeration enum; public EnumerationIterator (Enumeration enum) { this.enum = enum; }
public boolean hasNext () { return enum.hasMoreElements ( );}public Object next ( ) { return enum.nextElement ( );}
public void remove ( ) { throw new UnsupportedOperationException ( );}
}
Since we are adapting Enumeration to Iterator, the EnumerationIterator must implement the Iterator interface -- it has to look like the Iterator.
The Enumeration we are adapting. We’re using composition so we stash it in an instance variable.
hasNext ( ) and next () are implemented by delegating to the appropriate methods in the Enumeration.
For the remove ( ) we simply throw an exception.
Question: Some AC adapters do more than just change the interface -- they add other features like surge protection, indicator lights, and other bells and whistles.
If you were going to implement these kinds of features, what pattern would you use?
Summary
When you need to use an existing class and its interface is not the one you need, use an adapter.
An adapter changes an interface into one a client expects. Implementing an adapter may require little work or a great deal of
work depending on the size and complexity of the target interface.
There are two forms of adapter patterns: object and class adapters. Class adapters require multiple inheritance.
An adapter wraps an object to change its interface, a decorator wraps an object to add new behaviors and responsibilities.
The Template Method Pattern
Encapsulating Algorithms
On an encapsulation role…encapsulated object creation, method invocation, complex interfaces, ducks, pizzas…and now we encapsulate pieces of algorithms!
Time for some more caffeine….
Starbuzz Coffee Barista Training Manual
Baristas! Please follow these recipes precisely when preparing Starbuzz beverages.
Starbuzz Coffee Recipe(1) Boil some water(2) Brew coffee in boiling water(3) Pour coffee in cup(4) Add sugar and milk
Starbuzz Tea Recipe(1) Boil some water(2) Steep tea in boiling water(3) Pour tea in cup(4) Add lemon
The recipe for coffee and tea are very similar!
Whipping up some Coffee in Java public class Coffee { void prepareRecipe ( ) {
boilWater ( ); brewCoffeeGrinds ( ); pourInCup ( ); addSugarAndMilk (); }
public void boilWater ( ) { System.out.println(“Boiling water”);}public void brewCoffeeGrinds ( ) {
System.out.println (“Dripping coffee thru filter”);}public void pourInCup ( ) {
System.out.println(“Pouring into cup”);}public void addSugarAndMilk ( ) {
System.out.println (“Adding Sugar and Milk” );}
}
Recipe for coffee - each step is implemented as a separate method.
Each of these methods implements one step of the algorithm. There’s a method to boil the water, brew the coffee, pour the coffee in the cup, and add sugar and milk.
And now for the Tea…. public class Tea { void prepareRecipe ( ) {
boilWater ( ); steepTeaBag ( ); pourInCup ( ); addLemon (); }
public void boilWater ( ) { System.out.println(“Boiling water”);}public void steepTeaBag ( ) {
System.out.println (“Steeping the Tea”);}public void pourInCup ( ) {
System.out.println(“Pouring into cup”);}public void addLemon ( ) {
System.out.println (“Adding Lemon” );}
}
Very similar to the coffee - 2nd and 4th steps are different.
These methods are exactly the same
These methods are specialized to Tea
We have code duplication - that’s a good sign that we need to clean up the design. We should abstract the commonality into a base class since coffee and tea are so similar, right?? -- Give a class diagram to show how you would redesign the classes.
Sir, may I abstract your Coffee, Tea?
CaffeineBeverage prepareRecipe ( ) boilWater ( ) pourInCup ( )
Coffee prepareRecipe ( ) brewCoffeeGrinds ( ) addSugarAndMilk ( )
Tea prepareRecipe ( ) steepTeaBag ( ) addLemon ( )
Is this a good redesign? Are we overlooking some other commonality? What are other ways that Coffee and Tea are similar?
The boilWater( ) and pourInCup ( ) are shared by both subclasses, so defined in the superclass.
The prepareRecipe ( ) method differs in each subclass, so it is defined as abstract.
Each subclass( ) overrides the prepareRecipe ( ) method and implements its own recipe.
The methods specific to Coffee and Teac stay in the subclasses.
Each subclass implements its own recipe.
What else do they have in common?
Both the recipes follow the same algorithm:
(1) Boil some water
(2) Use hot water to extract the tea or coffee
(3) Pour the resulting beverage into a cup
(4) Add the appropriate condiments to the beverage.
These two are already abstracted into the base class.
These aren’t abstracted but are the same, they just apply to different beverages.
Can we abstract prepareRecipe ( ) too? Yes…
Abstracting PrepareRecipe ( )
Provide a common interface for the different methods• Problem : Coffee uses brewCoffeeGrinds ( ) and
addSugarAndMilk () methods while Tea uses steepTeaBag ( ) and addLemon ( ) methods
• Steeping and brewing are pretty analogous -- so a common interface may be the ticket: brew ( ) and addCondiments ()
The New Java Classes….
public abstract class CaffeineBeverage {final void prepareRecipe ( ) {
boilWater ( );brew ( );pourInCup ( );addCondiments ( );
}abstract void brew ( );abstract void addCondiments ( );void boilWater ( ) {
System.out.println (“Boiling Water”);}void pourInCup ( ) {
System.out.println(“Pouring into cup”);}
}
Because Coffee and Tea handle these in different ways, they are going to have to be declared as abstract. Let the subclasses worry about that stuff!
public class Tea extends CaffeineBeverage {public void brew ( ){
System.out.println (“Steeping the Tes”);}public void addCondiments ( ) {
System.out.println(“Adding Lemon”);}
}
public class Coffee extends CaffeineBeverage {public void brew ( ) {
System.out.println (“Dripping Coffee Thru the Filters”);}public void addCondiments ( ){
System.out.println(“Adding Sugar and Milk”);}
}
What have we done?
We have recognized that the two recipes are essentially the same, although some of the steps require different implementations. – So we’ve generalized the recipe and placed it in the base class.
– We’ve made it so that some of the steps in the recipe rely on the subclass implementations.
Essentially - we have implemented the Template Method Pattern!
Meet the Template Method public abstract class CaffeineBeverage {
void final prepareRecipe ( ) {
boilWater ( );
brew ( );
pourInCup ( );
addCondiments ( );}
abstract void brew () ;abstract void addCondiments ( );
void boilWater () {// implementation
}
void pourInCup ( ) {// implementation
}}
prepareRecipe ( ) is the template method here. Why? Because: (1) it is a method (2) it serves as a template for an algorithm. In this case an algorithm for making caffeinated beverages.
In the template, each step of the algorithm is represented by a method.
Some methods are handled by this class….
….and some are handled by the subclass.
Methods that need to be supplied by the subclass are declared abstract.
The Template Method defines the steps of an algorithm and allows subclasses to provide the implementation of one or more steps.
Behind the scenes….. Tea myTea = new Tea ( ); myTea.prepareRecipe ( ); boilWater ( ); brew ( ); pourInCup ( ); addCondiments ( );
Polymorphism ensures that while the template controls everything, it still calls the right methods.
The Template Method DefinedThe Template Method Pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
AbstractClass templateMethod ( ) primitiveOperation1 ( ) primitiveOperation2 ( )
ConcreteClassprimitiveOperation1 ( ) primitiveOperation2 ( )
primitiveOperation1 (); primitiveOperation2 ();
The template method makes use of the primitiveOperations to implement an algorithm. It is decoupled from the actual implementations of these operations.
The ConcreteClass implements the abstract operations, which are called when the templateMethod ( ) needs them.
There may be many ConcreteClasses each implementing the full set of operations required by the template method.
….and abstract versions of the operations used in the template method.
The Abstract Class contains the template method.
Hooked on the Template Method A hook is a method that is declared in the abstract class, but only given an empty or
default implementation. – Gives the subclasses the ability to “hook into” the algorithm at various points, if they wish;
they can ignore the hook as well.
public abstract class CaffeineBeverageWithHook { void prepareRecipe ( ) {
boilWater ( );brew ( );pourInCup ( );if (customerWantsCondiments ( ) ){
addCondiments ( );}
}abstract void brew ( );abstract void addCondiments ( );
void boilWater ( ) {System.out.println(“Boiling Water”);
}void pourInCup ( ) {
System.out.println(“Pouring into cup”);}boolean customerWantsCondiments ( ){
return true;}
}
We’ve added a little conditional statement that bases its success on a concrete method, customerWantsCondiments ( ). If the customer WANTS condiments, only then do we call addCondiments ( )
This is a hook, because a subclass can override this method but doesn’t have to.
If subclasses want to use the hook they simply override it!
Low LevelComponent
Low LevelComponent
DP: The Hollywood Principle
The Hollywood Principle gives us a way to prevent “dependency rot”– Dependency rot happens when you have high-level components depending on low-
level components depending on high level components depending on sideways components depending on low level components and so on….
With the Hollywood principle – We allow low level components to hook themselves into a system
– But high level components determine when they are needed and how.
– High level components give the low-level components a “don’t call us, we’ll call you” treatment.
The Hollywood Principle: Don’t call us, we’ll call you!
But high-level components control when and how.
A low-level component never calls a high-level component directly.
Low-level components can participate in the computation.
High Level Component
The Hollywood Principle and the Template Method
CaffeineBeverage prepareRecipe ( ) boilWater ( ) pourInCup ( ) brew ( ) addCondiments ( )
Coffee brew ( ) addCondiments ( )
Tea brew ( ) addCondiments ( )
Clients of beverages will depend on the CaffeineBeverage abstraction rather than a concrete Tea or Coffee, which reduces dependencies in the overall system.
CaffeineBeverage is our high-level component. It has control over the algorithm for the recipe, and calls on the subclasses only when they are needed for an implementation of a method.
The subclasses are used simply to provide implementation details.
Tea and Coffee never call the abstract class directly without being “called” first.
What other patterns make use of the Hollywood Principle?
Template Methods in the Wild
Template method is a very common pattern and you’re going to find lots in the wild!
Some examples:– Sorting with Template Method– Swinging with Frames
Sorting with Template Method Arrays - common operation - sort them! Designers of Java Arrays provide a handy template method for sorting. (simplified version of how it works - look at actual source for more
details.)
public static void sort (Object[] a) { Object aux [ ] = (Object [])a.clone () ;
mergeSort (aux, a, 0, a.length, 0); }
private static void mergeSort (Object [] src, Object [] dest, int low, int high, int off) {for (int I = low; I < high; I++ ) {
for (int j = I; j > low && ((Comparable)dest[j-1].compareTo((Comparable)dest[j]) > 0; j--) { swap (dest, j, j-1);
}}return;
}
The method sort () is a helper method that creates a copy of the array and passes it along as the destination array to the mergeSort ( ). It also passes along the length of the array and tells the sort to start at the first element.
The mergeSort () method contains the sort algorithm, and relies on an implementation of the compareTo ( ) method to complete the algorithm. Check out the actual src code for the nitty gritty details.
Think of this as the template method
compareTo ( ) is the method we need to implement to “fill out” the template method.
This is a concrete method already defined in the Arrays class.
Sorting some Ducks… Assume that you have an array of ducks to sort. How would you
do it? Use the sort ( ) template method in the Array to do the sort
– Need to implement the compareTo ( ) method -- to tell the sort ( ) how to compare ducks.
Any issues here?
In the Template method we typically would subclass something. An array doesn’t subclass anything. Reason: The designers of sort ( ) wanted it to be useful across all arrays, so they had to make sort ( ) a static method that could be used from anywhere. One more detail - because we are not using subclassing, the sort ( ) method needs to know that you have implemented the compareTo ( ) method. To handle this there is the Comparable interface that your class needs to implement. It has just one method - compareTo().
Comparing Ducks and Ducks public class Duck implements Comparable {
String name;int weight;public Duck (String name, int weight) {
this.name = name;this.weight = weight;
}public String toString ( ){
return name + “ weighs “ + weight;}
public int compareTo ( Object object ) {Duck otherDuck = (Duck) object;if (this.weight < otherDuck.weight) {
return -1;} else if (this.weight ==
otherDuck.weight) {return 0;
} else { //this.weight > otherDuck.weight
return 1;}
}}
public class DuckSortTestDrive {public static void main (String[] args){
Duck [ ] ducks = { new Duck (“Daffy”, 8),new Duck (“Dewey”, 2),new Duck (“Howard”, 7),new Duck (“Louie”, 2),new Duck (“Donald”, 10),new Duck (“Huey”, 2) };
System.out.println(“Before sorting”);display(ducks);
Arrays.sort (ducks);
System.out.println(“\n After Sorting”);display (ducks);
}public static void display (Duck[] ducks){
for (int j=0; j < ducks.length; j++) System.out.println(ducks[j]);
}}
Is this really a Template Method Pattern? The pattern calls for implementing an algorithm, and letting
subclasses supply the implementation of the steps. Array.sort ( ) is doing just that! Patterns in real life are often adaptations of the book patterns Designers of the Arrays sort ( ) method had some constraints:
– In general you can’t subclass Java Array and they wanted sort to be useful for all arrays
– For Array sort ( ) implementation:• static method was defined
• Comparison was deferred to the items being sorted.
– So yes this is a Template Method!
Swingin’ with Frames
JFrame - most basic Swing container and inherits a paint ( ) method. Default behavior of paint ( ) method - does nothing because it is a hook. By overriding the paint () method, you can insert yourself into JFrame’s
algorithm for displaying its area of screen and have your own graphic output incorporated into the JFrame.
Next up -- a simple example using JFrame to override the paint ( ) method.
Simple JFrame Example public class MyFrame extends JFrame {
public MyFrame (String title) {super (title);this.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
this.setSize ( 300, 300);this.setVisible (true);
}public void paint (Graphics graphics){
super.paint (graphics);String msg = “I rule!!”;graphics.drawString(msg, 100, 100);
}public static void main (String[] args){
MyFrame myFrame = new MyFrame (“Head First Design Patterns”);}
}
We’re extending JFrame, which contains a method update () that controls the algorithm for updating the screen. We can hook into that algorithm by overriding the paint () method.
Don’t look behind the curtain, just some initialization here….
JFrame’s update algorithm calls paint ( ). By default paint() does nothing…it’s a hook. We are overriding paint(), and telling the JFrame to draw a message in the window.
Applets Applets provide numerous hooks!
public class MyApplet extends Applet {
String message;
public void init ( ){message = “Hello World, I’m alive!”;repaint ( );}public void start ( ){message = “Now I’m starting up…”;repaint ( );}public void stop ( ) {message = “Now I’m being stopped…”;repaint ();}public void destroy ( ){// applet is going away}public void paint (Graphics g){g.drawString(message, 5, 15);}
}
The init hook allows the applet to do whatever it wants to initialize the applet the first time.
repaint ( ) is a concrete method in the Applet class that lets upper-level components know that the applet needs to be redrawn.
The start hook allows the applet to do something when the applet is just about to be displayed on the web page.
If the user goes to another page, the stop hook is used and the applet can do whatever it needs to do to stop its actions.
And the destroy hook is used when the applet is going to be destroyed, say, when the browser pane is closed. We could try and display something here…but what’s the point?
Well looky here! Applet also makes use of the paint() method as a hook.
Concrete applets make extensive use of hooks to supply their own behaviors. Because these methods are implemented as hooks, the applet isn’t required to implement them.
Summary (1/2)
A “template method” defines the steps of an algorithm, deferring to subclasses for the implementation of those steps.
The Template Method Pattern gives us an important technique for code reuse.
The template method’s abstract class may define concrete methods, abstract methods and hooks.
Abstract methods are implemented by subclasses. Hooks are methods that do nothing or default behavior in the
abstract class, but may be overridden in the subclasses. To prevent the subclasses from changing the algorithm in the
template method, declare the template method as final.
Summary (2/2)
The Hollywood Principle guides us to put decision making in high level modules that can decide how and when to call the low-level modules.
You’ll see lots of uses of the Template Method Pattern in real world code, but don’t expect it all (like any pattern) to be designed “by the book”.
The Factory Method is a specialization of the Template Method!
The Iterator and Composite Patterns
Well-Managed Collections!
Breaking news….. The Objectville Diner and Pancake House have merged! Menus
must be merged and have their separate identities! Owners agree on the implementation of the MenuItems.
public class MenuItem {
String name;String description;boolean vegetarian;double price;public MenuItem (String name,
String description, boolean vegetarian,double price ) {
// code here}// set of getter methods to get access to the fields.
}
Menu Implementations - Pancake House public class PancakeHouseMenu {
ArrayList menuItems;public PancakeHouseMenu ( ) { menuItems = new ArrayList ();
addItem (“Regular Pancake Breakfast”, “Pancakes with fried eggs, sausage”, false, 2.99);addItem (“Blueberry pancakes”,
“Pancakes made with fresh blueberries, true, 3.49); //other items}public void addItem (String name, String description,
boolean vegetarian, double price) {MenuItem menuItem = new MenuItem (name, description,
vegetarian, price);menuItems.add(menuItem);
}public ArrayList getMenuItems ( ) {
return menuItems;}// other methods
}
Uses an ArrayList, so the menu can be easily expanded.
To add a menuItem -- create a MenuItem object, add it to the arrayList
Menu Implementation - Diner public class DinerMenu {
static final int MAX_ITEMS = 6;MenuItem[] menuItems;int numberOfItems = 0;
public DinerMenu ( ) { menuItems = new MenuItem[MAX_ITEMS];
addItem (“Vegetarian BLT”, “(Fakin’) Bacon with Lettuce & tomato on whole wheat”, true, 2.99);addItem (“Soup of the Day”, “Soup of the Day, with a side of potato salad”, false, 3.29);
// other items}public void addItem (String name, String description, boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem (name, description, vegetarian, price);if (numberOfItems >= MAX_ITEMS){
System.err.println(“Sorry menu is full! Can’t add any more items”);}else {
menuItems[numerOfItems] = menuItem;numberOfItems = numberOfItems + 1;
}}public MenuItem[] getMenuItems ( ) {
return menuItems;}// other methods
}
Uses an Array: max size can be controlled no casting is needed
To add a menuItem -- create a MenuItem object, add it to the array if the max size has not been exceeded.
What’s the problem with having two different menu representations? What would it take to implement the functionality that a Java-
enabled Waitress may want:
– printMenu ( ): prints every item on the menu
– printBreakfastMenu (): prints just the breakfast items
– printLunchMenu ( ): prints just the lunch items
– printVegetarianMenu (): prints all the vegetarian items
– isItemVegetarian(name): given the name of the item, returns true if vegetarian, false otherwise
Implementing the Waitress1. To print all the items on each menu: PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu ( ); ArrayList breakfastItems = pancakeHouseMenu.getMenuItems ();
DinerMenu dinerMenu = new DinerMenu (); MenuItem[] lunchItems = dinerMenu.getMenuItems ( );
2. Print the items from the PancakeHouseMenu and the DinerHouseMenu -- need to loop over the ArrayList and Array respectively.
for (int j = 0; j < breakfastItems.size(); j++){
MenuItem menuItem = (MenuItem)breakfastItems.get(j);System.out.println(menuItem.getName ( ));// print out the description, vegetarian, and price
} for (int j = 0; j < lunchItems.length; j++) {
MenuItem menuItem = lunchItems[j];
3. Implementing the other methods is a variation on this theme. If another restaurant is added in, we would need three loops!
The methods look the same, but return different types -- ArrayList versus Array
What now?
Implementations can not be modified– Requires rewriting a lot of code in each respective
menu
Need: same interface for menus– getMenuItems() need to return a common object
type
How do we do that?
What now?
One of the key principles is : encapsulate what varies. What varies here?
Iteration caused by different collections of objects returned from the menus.
Can we encapsulate this?1. To iterate through the breakfast items we use size() and get () methods on
the Arraylist.2. To iterate through the lunch items we use the Array length field and the array
subscript notation on MenuItem Array.
Simple Iterator What if we create an object , an Iterator, that encapsulates how we iterate
through a collection of objects.
Iterator iterator = breakfastMenu.createIterator ( ); while (iterator.hasNext ( )) { MenuItem menuItem = (MenuItem)iterator.next (); }
Similarly,
Iterator iterator = lunchMenu.createIterator ( ); while (iterator.hasNext ( )){ MenuItem menuItem = (MenuItem)iterator.hasNext ( );
Meet the Iterator Pattern
The Iterator Design Pattern relies on an interface called the Iterator interface.
<<interface>> Iterator hasNext ( ) next ( )
A possible Iterator interface
Using the Iterator for the Diner Menu public interface Iterator {
boolean hasNext ( );Object next ( );
} // a concrete iterator public class DinerMenuIterator implements Iterator {
MenuItem[] items;int position = 0;
public DinerMenuIterator (MenuItem[] items) {this.items = items;
}public Object next ( ) {
MenuItem menuItem = item[position];position = position + 1;return menuItem;
}public boolean hasNext ( ) {
if (position >= items.length || items[position] == null) {return false;
} else {return true;
}}
}
We implement the Iterator interface
Position maintains the current position of the iteration over the array.
The constructor takes the array of menu items we are going to iterate over.
The next ( ) method returns the next item in the array and increments the position.
The hasNext () method checks to see if we’ve seen all the elements of the array and returns true if there are more to iterate over.
Because the Diner chef went ahead and allocated a max sized array, we need to check not only if we are at the end of the array, but also if the next item is null which indicates there are no more items.
Reworking the Diner Menu with Iterator public class DinerMenu {
static final int MAX_ITEMS = 6;int numberOfItems = 0;MenuItem[] menuItems ;
// constructor here
// addItem here
public MenuItem[] getMenuItems ( ) {return menuItems;
}
public Iterator createIterator ( ){return new DinerMenuIterator (menuItems);
}// other menu methods here
}
We’re not going to need the getMenuItems() method anymore and in fact we don’t want it because it exposes our internal implementation!
Here’s the createIterator () method. It creates a DinerMenuIterator from the menuItems array and returns it to the client.
We’re returning the Iterator interface. The client doesn’t need to know how the menuItems are maintained in the DinerMenu, nor does it need to know how the DinerMenuIterator is implemented. It just needs to use the iterators to step through the items in the menu.
Fixing up the Waitress Code public class Waitress {
PancakeHouseMenu pancakeHouseMenu;DinerMenu dinerMenu;
public Waitress (PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) {this.pancakeHouseMenu = pancakeHouseMenu;this.dinerMenu = dinerMenu;
}
public void printMenu ( ){Iterator dinerIterator = dinerMenu.createIterator ( );System.out.println(“\nLunch”);printMenu (dinerIterator);// similar set of statements for Breakfast menu
}
public void printMenu (Iterator iterator) {while (iterator.hasNext ( )) {
MenuItem menuItem = (MenuItem)iterator.next ( );// print it out
}}
}
Waitress takes the two objects as before
The printMenu ( ) creates two iterators one for each menu
Back to one loop! Here is where the printing occurs.
What have we done? The Menus are not well
encapsulated; we can see the Diner is using an ArrayList and the Pancake House an Array.
We need two loops to iterate through the MenuItems.
The Waitress is bound to concrete classes (MenuItem[] and ArrayList)
The Waitress is bound to two concrete Menu classes, despite their interfaces being almost identical.
The Menu implementations are now encapsulated. The Waitress has no idea how the Menus hold their collection of menu items.
All we need is a loop that polymorphically handles any collection of items as long as it implements the iterator.
The Waitress now uses an interface (Iterator).
The Menu interfaces are now exactly the same and uh, oh, we still don’t have a common interface, which means the Waitress is still bound to two concrete Menu classes.
Bird’s Eye View of Current Design
WaitressprintMenu ( )
PancakeHouseMenu
menuItems createIterator ( )
DinerMenu menuItems createIterator ( )
<<interface>> Iterator hasNext ( ) next ( )
PancakeHouseMenuIterator hasNext ( ) next ( )
DinerMenuIterator hasNext ( ) next ( )
The Iterator allows the Waitress to be decoupled from the actual implementation of the concrete classes. She doesnot need to know if a Menu is implemented with an Array or ArrayList or with PostIt notes! All she cares is that she can get an iterator to do her iterating.
Note that the iterator gives us a way to step through the elements of an aggregate without having the aggregate clutter its own interface with a bunch of methods to support traversal of its elements. It also allows the implementation of the iterator to live outside the aggregate --- in other words, we ‘ve encapsulated the iteration.
The waitress is still bound to two concrete Menu classesSolution: define a common interface for the PancakeHouseMenu and DinerMenu!
The Iterator Pattern DefinedThe Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying implementation.
The Iterator places the task of traversal on the iterator object, not on the aggregate, which simplifies the aggregate interface and implementation, and places the responsibility where it should be.
<<interface>> Aggregate createIterator ( )
ConcreteAggregate createIterator ( )
<<interface>> Iterator hasNext ( ) next ( ) remove ( )
ConcreteIterator hasNext ( ) next ( ) remove ( )
Client
DP: Single Responsibility
Every responsibility of a class is an area of potential change. More than one responsibility means more than one area of change.
This principle guides us to keep each class to a single responsibility.
We have studied the principle of single responsibility at the module level. What is it?
DP: A class should have only one reason to change.
The java.util.Iterator
The java.util.Iterator interface supports the Iterator pattern that we have discussed thus far.
The Java Collections Framework -- provides a set of classes and interfaces, including ArrayList, Vector, LinkedList, Stack and PriorityQueue.
All of these classes implement the Collections interface, and provide a method iterator () to return an instance of the java.util.iterator to iterate over the collection.
Using java.util.Iterator
WaitressprintMenu ( )
PancakeHouseMenu
menuItems createIterator ( )
DinerMenu menuItems createIterator ( )
<<interface>> Iterator hasNext ( ) next ( )
PancakeHouseMenuIterator hasNext ( ) next ( )
DinerMenuIterator hasNext ( ) next ( )
<<interface>> Menu createIterator ()
These now implement the Menu interface which means they need to implement the createIterator ( ) method.
We’re now using the ArrayList iterator supplied by java.util. We don’t need this anymore
DinerMenu returns a DinerMenuIterator from its createIterator() method because that’s the kind of iterator required to iterate over its Array of menu items.
Each concrete Menu is responsible for creating the appropriate concrete Iterator class -- java.util.Iterator or DinerMenuIterator.
The Waitress is decoupled from the implementation of the menus, so now we can use an Iterator to iterate over any list of menu items without having to know about how the list of items is implemented.
Iterator in Java 5 Iterators and Collections in Java 5:
– Added support for iterating over Collections so that you don’t even have to ask for an iterator!
Includes a new form of for statement -- for/in– Lets you iterate over a collection or an array without creating an iterator
explicitly.
for (Object obj: collection) {
…… }
ArrayList items = new ArrayList ( ); items.add(new MenuItem(“Pancakes”, “delicious pancakes”, true, 1.59); items.add(new MenuItem(“Waffles”, “yummy waffles”, true, 1.99); items.add(new MenuItem(“Toast”, “perfect toast”, true, 0.59);
for (MenuItem item: items) { System.out.println(“Breakfast item: “ + item); }
Is the Waitress ready for prime time? public void printMenu ( ){ Iterator pancakeIterator = pancakeHouseMenu.createIterator ( );
Iterator dinerIterator = dinerMenu.createIterator ( );Iterator cafeIterator = cafeMenu.createIterator ( );
System.out.println (“MENU\n-------\nBREAKFAST”);printMenu(pancakeIterator);
System.out.println(“\nLUNCH”);printMenu(dinerIterator);
System.out.println(“\nDINNER”);printMenu(cafeIterator);
} void printMenu (Iterator iterator) {
// iterate over the collection and print }
Whats wrong with this?We have done a good job of decoupling the menu implementation and extracting the iteration into an iterator. But we are still handling the menus with separate, independent objects --- we need a way to manage them together. Ideas?
Packaging into an ArrayList We could package the menus up into an ArrayList and then get its iterator to
iterate through each Menu. The code in the Waitress should be simpler and it could handle any number of menus.
public class Waitress {
ArrayList menus;public Waitress (ArrayList menus) {
this.menus = menus;}public void printMenu ( ) {
Iterator menuIterator = menus.iterator ( );while (menuIterator.hasNext ( )){
Menu menu = (Menu)menuIterator.next ( );printMenu (menu.createIterator());
}}
void printMenu (Iterator iterator) {
// no code changes here}
We do loose the name of the menus in this implementation.
Just when we thought it was safe … The Diner wants to add a new dessert “submenu” What does that mean?
– We have to support not only multiple menus, but menus within menus. Solutions: we could make the Dessert menu an element of the DinerMenu collection, but that won’t
work as it is now implemented.– DessertMenu will need to be implemented as a collection– We can’t actually assign a menu to a MenuItem array because the types are different.
Time for a change!
So what do we need?
We need some kind of a tree shaped structure that will accommodate menus, submenus, and menu items
We need to make sure we maintain a way to traverse the items in each menu that is at least as convenient as what we are doing now with iterators
We need to be able to traverse the items in a more flexible manner. – For instance, we might need to iterate over only the Diner’s
dessert menu, or we might need to iterate over the Diner’s entire menu, including the dessert menu.
Possibilities
All Menus
PancakeHouseMenu
DinerMenu
DessertMenu
MenuItems
Menus and submenus sub-structure naturally fit into a tree-like structure
Can accommodate menus, submenus and menuitems
The Composite Pattern DefinedThe Composite Pattern allows you to compose objects into tree structures to represent whole-part hierarchies. Composite lets clients treat individual objects and composition of objects uniformly.
1. We can create arbitrarily complex trees.
2. We can treat them as a whole or as parts
3. Operations can be applied to the whole or the part.
leaf
node
Composite Pattern Structure
Component operation ( ) add (Component) remove (Component) getChild (int)
Composite operation ( ) add(Component) remove (Component) getChild (int)
Leaf operation ( )
Client
The client uses the Component interface to manipulate the objects in the composition.
The Component defines an interface for all objects in the composition: both the composite and the leaf nodes.
The Component may implement a default behavior for add ( ), remove (), getChild() and its operations.
Note that the leaf also inherits methods like add(), remove(), and getChild(), which don’t make a lot of sense for a leaf node. We will come back to this issue!
A leaf has no children
A Leaf defines the behavior for the elements in the composition. It does this by implementing the operations the Composite supports. The Composite’s role is to define
the behavior of the components having children and to store child components
The Composite also implements the Leaf-related operations. Note that some of these may not make sense on a Composite so in that case an exception might be generated.
Designing Menus with Composite
MenuItem getName ( ) getDescription ( ) getPrice ( ) isVegetarian ( ) print ( )
Menu menuComponents getName ( ) getDescription ( ) print ( ) add (Component) remove(Component) getChild (int)
MenuComponent getName () getDescription () getPrice () isVegetarian () print ( ) add(Component) remove(Component) getChild (int)
Waitress
The Waitress is going to use the MenuComponent interface to access both Menus and MenuItems.
Here are the methods for manipulating the components: Menu and MenuItem.
Both MenuItem and Menu override the print() method.
MenuItem overrides the methods that make sense, and uses the default implementations (Unsupported Exception, for example) in MenuComponent for those that don’t make sense (like add())
MenuComponent represents the interface for both MenuItem and Menu. We’ve used an abstract class here because we want to provide default implementations for these methods.
We have some of the same methods from our previous versions of MenuItem and Menu, and we’ve added the print()
Menu also overrides the methods that make sense, like a way to add and remove menu items (and submenus!) from the menuComponents. In addition, we can use getName() and getDescription() methods to return the name and description of the menu.
An Observation First we say: One Class, One Responsibility. Composite is a pattern with two responsibilities in one class:
manages a hierarchy and it performs operations related to Menus.
In the Composite pattern we trade the Single Responsibility design principle for transparency.– The client can treat both composites and leaf nodes uniformly
We lose: safety because the client may try to do something inappropriate or meaningless.– We could take the design in the other direction and separate out the
responsibilities into interfaces. This could make the design safe.– We would loose transparency in this case and our code would have to use
conditionals and the instanceOf operator.
Flashback to the Iterator - A Composite Iterator To implement a Composite Iterator we add the createIterator () method in
every component. – We add a createIterator () method to the abstract MenuComponent. This
means that each Menu and MenuItem will need to implement this method. It also means that calling createIterator() on a composite should apply to all children of the composite.
Implementations in Menu and MenuItem:
public class Menu extends MenuComponent {
// other code does not change public Iterator createIterator ( ) {
return new CompositeIterator (menuComponents.iterator ( ));}
} public class MenuItem extends MenuComponent {
// other code does not changepublic Iterator createIterator ( ) {
return new NullIterator ( );}
}
Here we’re using a new iterator called CompositeIterator. It knows how to iterate over any composite. We pass it the current composite’s iterator.
NullIterator coming up….
The Composite Iterator - A Serious Iterator import java.util.*; public class CompositeIterator implements Iterator {
Stack stack = new Stack ( );public CompositeIterator (Iterator iterator) {stack.push(iterator);
}public Object next ( ) {if (hasNext ( )){Iterator iterator = (Iterator) stack.peek();MenuComponent component = (MenuComponent) iterator.next ( );if (component instanceOf Menu) {stack.push (component.createIterator());}return component;} else {return null;} }public boolean hasNext ( ) {if (stack.empty()) {return false;} else {Iterator iterator = (Iterator) stack.peek ( );if (!iterator.hasNext ( )) {stack.pop();return hasNext ( );} else {return true;} } }public void remove ( ){throw new UnsupportedOperationException () ;}
}
Like all iterators, we’re implementing the java.util.Iterator interface.
The iterator of the top level composite we’re going to iterate over is passed in. We throw that in a stack data structure.
When the client wants the next element we first make sure there is one by calling hasNext ( )
If there is a next element, we get the current iterator off the stack and get its next element.
If that element is a menu, we have another composite that needs to be included in the iteration, so we throw it on the stack. In either case, we return the component.
To see if there is a next element, we check to see if the stack is empty;
Otherwise, we get the iterator off the top of the stack and see if it has a next element. If it doesnot we pop it off the stack and call hasNext ( ) recursively.
We are not supporting remove, just traversal.
The Null Iterator A MenuItem has nothing to iterate over. So how do we handle the
createIterator () implementation?–Choice 1: return null
• We could return null, and have conditional code in the client to check if a null was returned or not.
–Choice 2: • Return an iterator that always returns a false when hasNext ( ) is called. ---
create an iterator that is a no-op.
public class NullIterator implements Iterator {public Object next () {
return null; }
public boolean hasNext ( ) { return false;
}public void remove () {
throw new UnsupportedOperationException ();}
}
Give me the vegetarian menu… public class Waitress {
MenuComponent allMenus;public Waitress (MenuComponent allMenus) {
this.allMenus = allMenus;}public void printMenu ( ){
all.Menus.print ();}public void printVegetarianMenu ( ) {
Iterator iterator = allMenus.createIterator ( );System.out.println(“\n VEGETARIAN MENU\n-----”);while (iterator.hasNext ( )) {
MenuComponent menuComponent = (MenuComponent) iterator.next ( );try {
if (menuComponent.isVegetarian()) {menuComponent.print();
}catch (UnsupportedOperationException e) { }
}}
}
print() is only called on MenuItems, never on composites. Can you see why?
We implemented isVegetarian() on the Menus to always throw an exception. If that happens we catch the exception, but continue with the iteration….
The printVegetarianMenu ( ) method takes the allMenu’s composite and gets its iterator. This will be our CompositeIterator.
Exceptions and Program Logic…. In general, using exceptions to implement program logic is a big no, no!
– Yet that’s exactly what we are doing with the isVegetarian() method. We could have checked the runtime type of the Menu component with
instanceOf to make sure it’s a MenuItem before making the call to isVegetarian(). But in the process we would lose transparency.
We could also change isVegetarian() in the Menus to return a false. This provides a simple solution and we keep our transparency.
We choose to go for clarity - we want to communicate that for the Menus this really is an unsupported operation. It also allows for someone to come along and implement a reasonable isVegetarian ( ) method for Menu and have it work with existing code.
Summary (1/2)
An iterator allow access to an aggregate’s elements without exposing its internal structure.
An iterator takes the job of iterating over an aggregate and encapsulates it in another object.
When using an iterator, we relieve the aggregate of the responsibility of supporting operations for traversing its data.
An iterator provides a common interface for traversing the items of an aggregate, allowing us to use polymorphism when writing code that makes use of the items of the aggregate.
We should strive to assign only one responsibility to each class.
Summary (2/2)
The Composite Pattern provides a structure to hold both the individual objects and composites.
The Composite Pattern allows clients to treat composites and individual objects uniformly.
A Component is any object in a composite structure. Components may be other composites or leaf nodes.
There are many design tradeoffs in implementing the Composite. You need to balance transparency and safety with your needs.
The King of Compound Patterns
Meet the Model-View-Controller
Picture your favorite MP3 player– You can use its interface to add new songs, manage
play lists and rename tracks– The player maintains
• Database of all your songs along with associated names and data.
• Plays the song• Updates the interface constantly with current song, running
time and so on
Underneath the covers --- Model View Controller
Model View Controller
class Player { play ( ) { } rip ( ) { } burn ( ) { } }
Controller
Model
View
You use the interface and your actions go to the controller
“ Play new song”
Controller manipulates the model
Controller asks Player model to begin playing the song
Model tells the view the state has changed
The model notifies the view of a change in its state.
You see the song display update and hear the new song playing
The view display is updated for you.
The model contains all the state, data, and application logic needed to maintain and play mp3s.
A Closer Look…. Lets see the nitty gritty details of how this MVC pattern works….
– Step through the relationships among the model
– Take a look from Design pattern perspective.
class Player { play ( ) { } rip ( ) { } burn ( ) { } }
Controller
Model View
VIEW:Gives you a presentation of the model. The view usually gets the state and data it needs to display directly from the model.
CONTROLLER:Takes user input and figures out what it means to the model.
MODEL:The model holds all the data, state and application logic. The model is oblivious to the view and controller, although it provides an interface to manipulate and retrieve its state and it can send notifications of state changes to the Observer.
(1) The user did something
(2) Change your state
(3) Change your display
(4) I have changed
(5) I need your state information Here’s the model; it handles all application data and logic.
This is the user interface
Here’s the creamy controller; it lives in the middle.
A Closer Closer Look….(1) You are the user -- you interact with the view
– The view is your window to the model. When you do something to the view (like click the Play button), then the view tells the controller what you did. It’s the controller’s job to handle that.
(2) The controller asks the model to change its state– The controller takes your actions and interprets them. If you click on a button, it’s the controller’s job
to figure out what that means and how the model should be manipulated based on that action.
(3) The controller may also ask the view to change– When the controller receives an action from the view, it may need to tell the view to change as a result.
For example, the controller could enable or disable certain buttons or menu items in the interface.
(4) The model notifies the view when its state has changed.– When something changes in the model, based on either some action you took (like clicking a button) or
some other internal change (like the next song in the playlist has started), the model notifies the view that its state has changed.
(5) The view asks the model for state– The view gets the state it displays directly from the model. For instance, when the model notifies the
view that a new song has started playing, the view requests the song name from the model and displays it. The view might also ask the model for state as the result of the controller requesting some change in the view.
Looking at MVC through patterns-colored glasses MVC is set of patterns together in the same design. Model uses Observer to keep views and controllers
updated on the latest state changes. View and Controller implement a Strategy Pattern
– Example: Controller is the behavior of the view and can be easily exchanged with another controller if you want different behavior.
View also uses a pattern internally to manage the windows buttons and other components of the display => the Composite Pattern
A Closer Look….
class Player { play ( ) { } rip ( ) { } burn ( ) { } }
Controller
Model
View
(1) The user did something
(2) Change your state
(3) Change your display
(4) I have changed
(5) I need your state information
Strategy:The View and the Controller implement the classic Strategy Pattern: the view is an object that is configured with a strategy. The view is concerned only with the visual aspects of the application, and delegates to the controller for any decisions about the interface behavior. Using the Strategy pattern also keeps the view decoupled from the model, because it is the controller that is responsible for interacting with the model to carry out user requests. The view knows nothing about how it gets done.
The display consists of a nested set of windows, panels, buttons, text labels and so on. Each display component is a composite (like a window) or a leaf (button). When the controller tells the view to update, it only has to tell the top view component, and the Composite takes care of the rest.
The model implements the Observer Pattern to keep the interested objects updated when the state changes occur. Using the Observer Pattern keeps the model completely independent of the views and the controllers. Its allows us to use different views with the same model, or even multiple views at once.
Observer
My state has changedObservable
Model
View
I’d like to register as an observer
Any object that’s interested in state changes in the model registers with the model as an observer.
Observers
All these observers will be notified whenever state changes in the model.
View
Model
Controller
The model has no dependencies on viewers or controllers!
class Foo { void bar ( ) { doBar(); } }
Strategy
The user did something
View
Controller
Controller
The view delegates to the controller to handle the user actions.
The controller is the strategy for the view -- it’s the object that knows how to handle the user actions.
We can swap another behavior for the view by changing the controller.The view only worries about presentation, the controller worries
about translating user input to actions on the model.
Composite
View
Window
Set BPM
Set<< >>
paint ()
The view is a composite of GUI components (labels, buttons, text entry, etc.). The top level component contains other components, which contain other components, and so on until you get to the leaf nodes.
Using MVC to control the beat…
Time to be a DJ and start mixing with a beat! The Java DJ view:
View
Current BPM: 120
A pulsing bar shows the beat in real time
A display shows the current BPMs and is automatically set whenever the BPM changes.
120
Control
Enter BPM
Set<< >>
You can enter a specific BPM and click the Set button to set a specific beats per minute, or you can use the increase and decrease buttons for fine tuning.
The view has two parts, the part for viewing the state of the model and the part for controlling things.
Decreases the BPM by one beat per minute. Increases the BPM by one beat per minute.
The Controller is in the middle…
The controller sits between the view and the model. It takes your input, like decreasing the BPM and turns it into an action on the model to decrease the BPM.
Lets not forget the model underneath
on ( ) off ( )
setBPM ( )
getBPM ( )
Beat Model
The BeatModel is the heart of the application. It implements the logic to start and stop the beat, set the beats per minute, and generate the sound.
The model also allows us to obtains its current state through the getBPM( ) method.
Building the pieces
public interface BeatModelInterface { void initialize ( );
void on ( );void off ( );void setBPM (int bpm);int getBPM ( );void registerObserver (BeatObserver o);void removeObserver (BeatObserver o);void registerObserver (BPMObserver o);void removeObserver (BPMObserver o);
}
This gets called after the BeatModel is instantiated.
These methods turn the beat generator on and off.
This method sets the beats per minute. After it is called, the beat frequency changes immediately.
The getBPM ( ) method returns the current BPMs, or 0 if the generator is off.
We’ve split this into two kinds of observers: observers that want to be notified on every beat, and observers that just want to be notified with the beats per minute changes.
This should look familiar, these methods allow objects to register as observers for state changes.
These are the methods that a controller will use to direct the model based on user interaction.
These methods allow the view and controller to get state and become observers.
Now lets take a look at the concrete BeatModel class…. public class BeatModel implements BeatModelInterface, MetaEventListener { Sequencer sequencer; ArrayList beatObservers = new ArrayList(); ArrayList bpmObservers = new ArrayList(); int bpm = 90;
// other instance variables public void initialize() {
setUpMidi(); buildTrackAndStart();
} public void on() { sequencer.start(); setBPM(90); } public void off() { setBPM(0); sequencer.stop(); } public void setBPM (int bpm) { this.bpm = bpm; sequencer.setTempoInBPM(getBPM()); notifyBPMObservers(); } public int getBPM() { return bpm; }
void beatEvent ( ) {notifyBeatObservers ( );
}// code to register and notify observers// Lots of MIDI code to handle the beat.
}
We implement the BeatModelInterface. This is needed for the
MIDI code.
The sequencer is the object that knows how to generate the real beats (that you can hear!)
The ArrayLists hold the two kinds of Observers
bpm holds the frequency of beats. Default = 90.
This method does setup for the sequencer and sets up the beat tracks for us. The on() and off ( ) starts
and shuts off the sequencer.
(1) Sets the bpm instance variable (2) Asks the sequencer to change its beats (3) Notifies all BPM observers that the BPM has changed.
The beatEvent ( ) method, which is not in the BeatModelInterface, is called by the MIDI code whenever a new beat starts. This notifies all BeatObservers that a new beat has just occurred.
Implementing the View (just an outline!) public class DJView implements ActionListener, BeatObserver, BPMObserver {
BeatModelInterface model;ControllerInterface controller;JFrame viewFrame;JPanel viewPanel;BeatBar beatBar;JLabel bpmOutputLabel;
public DJView ( ControllerInterface controller, BeatModelInterface model) {this.controller = controller;this.model = model;model.registerObserver ( (BeatObserver) this);model.registerObserver ((BPMObserver)this);
}
public void createView ( ){// create all Swing components here
}public void updateBPM ( ) {
int bpm = model.getBPM ( );if (bpm == 0) {
bpmOutputLabel.setText (“offline”);} else {
bpmOutputLabel.setText(“Current BPM: “ + model.getBPM ( ));}
}public void updateBeat ( ) {
beatBar.setValue (100);}
}
DJView is an observer for both the real-time beats and BPM changes.
The view holds a reference to both the model and the controller.
The updateBPM ( ) method is called when a state change occurs in the model. When that happens we update the display with the current BPM. We can get this value by requesting it directly from the model.
Likewise, the updateBeat ( ) method is called when the model starts a new beat. When that happens, we need to pulse our “beatbar”. We do this by setting it to its maximum value and letting it handle the animation of the pulse.
The DJView continued… (the user interface control) public class DJView implement ActionListener, BeatObserver, BPMObserver {
BeatModelInterface model;ControllerInterface controller;Jlabel bpmLabel;JTextField bpmTextField;Jbutton setBPMButton;Jbutton increaseBPMButton;Jbutton decreaseBPMButton;JMenuBar menuBar;Jmenu menu;JMenuItem startMenuItem;JMenuItem stopMenuItem;
public void createControls ( ) {// create all Swing components
}public void enableStopMenuItem ( ){
stopMenuItem.setEnabled(true);}public void disableStopMenuItem ( ){
stopMenuItem.setDisabled (true);}// same for startMenuItem
public void actionPerformed (ActionEvent event) {if (event.getSource ( ) == setBPMButton) {
int bpm = Integer.parseInt (bpmTextField.getText ( ) );controller.setBPM (bpm);
} else if (event.getSource( ) == increaseBPMButton) {controller.increaseBPM () ;
} else if (event.getSource( ) == decreaseBPMButton) {controller.decreaseBPM () ;
}}
}
If the Set button is clicked then it is passed on to the controller along with the new bpm.
Likewise if increase or decrease buttons are clicked, this information is passed on to the controller.
This method is called when a button is clicked.
Now for the Controller….
Remember - the controller is the strategy that we plug into the view.
What does a Strategy pattern look like? What do we need?
public interface ControllerInterface {void start ( );void stop ( );void increaseBPM ( );void decreaseBPM ( );void setBPM (int bpm);
}
Here are all the methods that a view can call on the controller
These should all look familiar after seeing the model’s interface. You can start and stop the beat generation, and change the BPM. This interface is “richer” than the BeatModel interface because you can adjust the BPMs with increase and decrease.
The Controller public class BeatController implements ControllerInterface { BeatModelInterface model; DJView view; public BeatController(BeatModelInterface model) { this.model = model; view = new DJView(this, model); view.createView(); view.createControls(); view.disableStopMenuItem(); view.enableStartMenuItem(); model.initialize(); } public void start() { model.on(); view.disableStartMenuItem(); view.enableStopMenuItem(); } public void stop() { model.off(); view.disableStopMenuItem(); view.enableStartMenuItem(); } public void increaseBPM() { int bpm = model.getBPM(); model.setBPM(bpm + 1); } public void decreaseBPM() { int bpm = model.getBPM(); model.setBPM(bpm - 1); } public void setBPM (int bpm) {
model.setBPM (bpm); }}
Controller implements the ControllerInterface!
The controller is the creamy stuff in the middle of the MVC oreo cookie, so it is the object that gets to hold on to the view and the model and glues it all together.
The controller is passed the model in the constructor and then creates the view.
When you choose Start from the user interface menu, the controller turns the model on and then alters the user interface to that the start menu item is disabled and the stop menu item is enabled.
Note: the controller is making the intelligent decision for the view. The view just knows how to turn menu items on and off; it doesn’t know the situations in which it should disable or enable them.
Putting it all together… public class DJTestDrive {
public static void main (String[] args) {BeatModelInterface model = new BeatModel ( );ControllerInterface controller = new BeatController (model);
} }
First create the model…
…..then create a controller and pass it the model. Remember, the controller creates the view, so we don’t have to do that.
Question
You have a beat rate and a pulse? What does that sound like? -- A heartbeat
What would you need to do to modify your MVC beat model to work with a heartbeat?
MVC and the Web With the coming of the Web, the MVC model was adapted to fit
the browser/server model. – The prevailing adaptation is called Model 2.
Here’s how Model 2 works:
(1) HTTP Request
(2) Instantiates
(3)
(4)(5) HTTP Response
JSP/view
Servlet/controller
Client
Model/DB/buisness logicbean
The servlet acts as a controller and processes the request - most likely making requests on the model (db). The result of processing the request is usually bundled up in the form of a Javabean
The controller forwards control to the view. The view is represented by a JSP. The JSP’s only job is to generate the page representing the view of the model.
Summary The MVC Pattern is a compound pattern consisting of the Observer, Strategy and Composite
patterns.
The model makes use of the Observer pattern so that it can keep observers updated, yet stay decoupled from them.
The controller is the strategy for the view. The view can use different implementations of the controller to get different behavior.
The view uses Composite Pattern to implement the user interface, which usually consists of nested components like panels, frames, and buttons.
These patterns work together to decouple the three players in the MVC model, which keeps designs clear and flexible.
The Adapter pattern can be used to adapt a new model to an existing view and controller.
Model 2 is an adaptation of the MVC for web applications.
In Model 2, the controller is implemented as a servlet and JSP and HTML implement the view.