Design patterns are known and tested solutions to common problem. In software engineering we constantly come across similar problems. The same problems or tasks need to be programmed again and again, hence patterns. Design patterns catalog and document these solutions.They are built on industry knowledge of what works and why. We will look at what design patterns are, their history and the structure of documenting patterns.
As an example we look at the Observer pattern.
We will also look at Liskov Substitution Principle and the Open Close Principle, both which are very useful in building enterprise systems. Finally we look at creating objects.
6. Design Patterns
Design pattern is a general solution to a common
problem in software design
– Systematic approach for problems that reoccur in software
development
– Not complete solution but starting point for design
– Not code ready to use
– Patterns have names and definitions
– Built on common practices
Patterns should not be language dependant
– However patterns apply for types of programming
languages
7. History
Patterns originated as an architectural concept
“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”
- Christopher Alexander
8. History
Landmark book from 1995:Design Patterns:
Elements of Reusable Object-Oriented Software
– Gang of Four (GoF)
– Term Design Pattern is
borrowed from the
construction industry
Several books on patterns
have been published since
– Head First Design Patterns
for example
9. Vintage Design Patterns
Design Patterns are like good red wine
– You cannot appreciate them at first
– As you study them you learn the
difference between plonk and vintage,
or bad and good designs
– As you become a connoisseur you experience the
various textures you didn’t notice before
Warning:
– Once you are hooked, you will no longer be satisfied
with inferior designs
Dr. Heinz Kabutz (http://www.javaspecialists.co.za)
10. Pattern Classification
Design patterns can be classified based on
multiple criteria
– Basic underlying problem they solve
Classification
– Fundamental patterns
– Creational patterns
– Structural patterns
– Behavioral patterns
– Concurrency patterns
11. Enterprise Patterns Classification
Domain Logic Patterns
Data Source Architectural Patterns
Object-Relational Behavioral Patterns
Object-Relational Structural Patterns
Object-Relational Metadata Mapping Patterns
Web Presentation Patterns
Distribution Patterns
Offline Concurrency Patterns
Session State Patterns
Base Patterns
12. Which of these statements is not true
A) Design Patterns are based on solutions from practice
B) Design Patterns are ideas not code
C) Design Patterns are based on specific programming languages
D) Design Patterns can have ambiguous names
QUIZ
✔
14. Structure of Patterns
Name
The Intent
The Sketch
Motivation
How it Works
When to Use it
Further Reading
Examples
15. The Name
Pattern names are important
– Need to create a vocabulary
– Need to describe the pattern well
– Avoid ambiguity and misunderstanding
Problems with names
– Authors are using different names for same pattern
• Data Access Object and Table Data Gateway
• Dependency Injection and Inversion of Control
– Authors are using same name for different patterns
• Example: Value Object is used for two similar patterns
16. The Intent
Sums up the pattern in a sentence or two
– Value Object:
A small simple object, like money or date range, whose
equality isn’t based on identity
17. The Sketch
Visual representation of the pattern, often but
not always a UML diagram
18. Motivation
Description of a motivating problem for the
pattern
– Problem description
– May not be the only problem for the pattern
Example:
– Layered supertype
It’s not uncommon for all the objects in a layer to have
methods you don’t want to have duplicated
throughout the system. You can move this behavior
into a common Layer Supertype
19. How it Works
Describes the solution
– Implementation Issues
– Variations
– Independent of any particular platform
– Platform dependent sections are identified
– UML Diagrams if applicable
Plugin example
20. When to Use It
Describes when the pattern should be used
– Trade-offs
– Comparisons
Layered Supertype example
– Use Layer Supertype when you have common
features from all objects in a layer
21. Examples
Example code in Java or C#
– Layer Supertype
Not working code
– pseudo code to give idea
class DomainObject...
private Long ID;
public Long getID()
{
return ID;
}
public void setID(Long ID)
{
this.ID = ID;
}
public DomainObject(Long ID)
{
this.ID = ID;
}
22. Using Design Patterns
How to use design patterns?
– Problem is the patterns can be complex and detailed
– Usually they are generic and abstract
Ways to study patterns
– Implement them in test code
– Sketch a class diagram in your context to see the
class dependencies
– Form a “Study group” to discuss the patterns
– Learn the vocabulary
– Practice, practice, practice
23. Problems with Patterns
Ambiguity in Vocabulary
– Same pattern has different names
– Different Patterns have same name
Appling the wrong pattern
– Over-designing the solution
– Patterns design for one language might not be
needed in another
Not solving the original problem
– Using Remote Façade instead of avoiding network
latencies
– Using EJB Entity Beans
24. Job interview question
You are given the assignment of creating a component that needs to
know sales statistics of Lottery tickets. You know that there is a
another component in the system, Sale Server, that handles the sale.
You need real-time information. What would you suggest?
EXERCISE
25. Sale server Bingo
First proposal: Sale Server will call Bingo
Problem is that the Sale Server developer refuses to make a call to
a specific game. His argument is that Sale Server should be for
sale, and not be cluttered with game specific code.
Another solution is needed.
30. The Weather Monitoring Example
Task
– We need to implement measurementsChanged so
that it updates three different displays for current
conditions, weather stats, and forcasts
– measurementsChanged is called any time data
changes, we don’t know or care how this method is
called
– Three display types must be updated
– The system must be expandable – new display types
will be added
31. The Weather Monitoring Example
WeatherData class
public class WeatherData
{
// instance variable declarations
public void measurementsChanged()
{
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionsDisplay.update (temp, humidity, pressure);
statisticsDisplay.update (temp, humidity, pressure);
forcastConditionsDisplay.update (temp, humidity, pressure);
}
...
}
32. Quiz
Based on our first implementation, which of the
following apply
A. We are coding to concrete implementation not
abstractions
B. For every new display element we need to alter code
C. We have no way to add (or remove) display elements at
runtime
D. The display elements don’t implement a common
interface
E. We have not encapsulated the part that changes
F. We are violating encapsulation of the WeatherData
33. The Weather Monitoring Example
WeatherData class
public class WeatherData
{
// instance variable declarations
public void measurementsChanged()
{
float temp = getTemperature();
float humidity = getHumidity();
float pressure = getPressure();
currentConditionsDisplay.update (temp, humidity, pressure);
statisticsDisplay.update (temp, humidity, pressure);
forcastConditionsDisplay.update (temp, humidity, pressure);
}
...
}
By coding to concreate implementation
we have no way to add or remove
displays without code change
Interface is that same for
all
34. Observer
One or more observers or listeners are registered to
observe an event which may be raised by the
observed object (the subject)
Sometimes called publish/subscribe
– Similar to call-back handlers
– One-to-Many relationship
Benefits
– Listening object gets information when needed
– Subject does not become dependent on multiple observers
37. Loose Coupling
When two object are loosley coupled, the can
interact but they have very little knowledge of each
other
The Observer Pattern loosley coupled design
– The only thing the subject knows about observer is that it
implements a ceratain interface
– We can add new observers at any time
– We never need to modify the subject to add new types of
observers
– We can reuse subjects or observers independent of each
other
39. Weather Station Example
public interface Subject
{
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
public interface DisplayElement
{
public void display();
}
public interface Observer
{
public void update(float temp, float humidity, float pressure);
}
40. Weather Station Example
public class WeatherData implements Subject
{
private ArrayList observers;
private float temperature, humidity, pressure;
public WeatherData()
{
observers = new ArrayList();
}
public void registerObserver(Observer o)
{
observers.add(o);
}
public void removeObserver(Observer o)
{
int i = observers.indexOf(o);
if (i>= 0)
observers.remove(i);
}
41. Weather Station Example
public void notifyObservers()
{
for (int i = 0; i<observers.size(); i++) {
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged()
{
notifyObservers();
}
// Test code
public void setMeasurement(float temperature, float humidity,
float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
this.measurementsChanged();
}
42. Weather Station Example
public class CurrentConditionsDisplay implements Observer,
DisplayElement
{
private float temperature, humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature + "C " +
"Humidity: " + humidity + "%");
}
}
Registering
this as an
observer
The subject
will call
update
43. Weather Station Example
public class WeatherStation
{
public static void main(String[] args)
{
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new
CurrentConditionsDisplay(weatherData);
weatherData.setMeasurement(15, 50, 30);
}
}
Current conditions: 15.0C Humidity: 50.0%
44. Loose Coupling
When two object are loosley coupled, the can
interact but they have very little knowledge of each
other
The Observer Pattern loosley coupled design
– The only thing the subject knows about observer is that it
implements a ceratain interface
– We can add new observers at any time
– We never need to modify the subject to add new types of
observers
– We can reuse subjects or observers independent of each
other
47. Overriding Behavior
RubberDuck overwrote fly to do nothing
– Any use of Duck that expects fly behavior will not
work correctly
– Users of the base class (Duck) should expect same
functionality
– Violation of the Liskov Substitution Principle
48. The Liskov Substitution Principle
Subtypes must be
substitutable for their base
types. Code that uses
references to base class must
be able to use objects of
derived classes without
knowing it.
Barbara
Liskov
49. The Liskov Substitution Principle
All code operating with reference to the base
class should be completely transparent to the
type of the inherited object
It should be possible to substitute an object of
one type with another within the same class
hierarchy
Inheriting classes should not perform any
actions that will invalidate the assumptions
made by the base class
50. LSP Example
public class Rectangle {
protected int _width;
protected int _height;
public int getWidth() {
return _width;
}
public int getHeight() {
return _height;
}
public void setWidth(int width) {
_width = width;
}
public void setHeight(int height) {
_height = height;
}
}
51. LSP Example
public class Square extends Rectangle {
public void setWidth(int width) {
_width = width;
_height = width;
}
public void setHeight(int height) {
_height = height;
_width = _height;
}
}
Implementation convenience
52. LSP Example
import junit.framework.Assert;
import org.junit.Test;
public class RectangleTests {
@Test
public void areaOfRectangle() {
Rectangle r = new Square();
r.setWidth(5);
r.setHeight(2);
// Will Fail - r is a square and sets
// width and height equal to each other.
Assert.assertEquals(r.getWidth() * r.getHeight(),10);
}
}
54. The Open-Closed Principle
Software entities like
classes, modules and
functions should be open for
extension but closed for
modifications
55. The Open-Closed Principle
Design and write code in a fashion that adding
new functionality would involve minimal changes
to existing code
– Most changes will be handled as new methods and
new classes
– Designs following this principle would result in
resilient code which does not break on addition of
new functionality
56. public class ResourceAllocator
{
...
public int allocate(intresourceType)
{
intresourceId;
switch (resourceType)
{
case TIME_SLOT:
resourceId = findFreeTimeSlot();
markTimeslotBusy(resourceId);
break;
case SPACE_SLOT:
resourceId = findFreeSpaceSlot();
markSpaceSlotBusy(resourceId);
break;
...
}
return resourceId;
}
...
Resource Allocator Example
Holy Buckets!!
I need to change
the class for new
types!!! Horrible!
57. Resource Allocator Example
Design for extensions
List resources = new ArrayList();
...
public int allocate(intresourceType)
{
int resourceId = findFreeResource(resourceType);
markAsBusy(resourceId);
return resourceId;
}
58. Another Example
protected String normalize(char cCharacter)
{
switch(cCharacter) {
case '<': return "<";
case '>': return ">";
case '&’: return "&";
case '"’: return """;
default: return ""+cCharacter;
} }
This is not complete
This is common problem – a library must exists
If making it yourself, a Map would be better
What is wrong with
this code?
60. Task
We need to create program that reads feeds
Feed can be RSS news, XML or what ever
The program must be loosely coupled
New feed types will come
61. Creating Objects
Where does the creation take place?
Enterprise Application
This stays the same
This that is added
62. Call-back Handlers
Inverting the Dependency
– Let a class call you back
Example
– sort routine, reading records
ReaderProcess RssFeedReader
processEntry
processEntry
processEntry
Read
63. Example: Reading RSS
Process to read an RSS feed
– The FeedReader define the role of such readers
– Concrete readers must implement read and accept a
call-back handler to get the results back
public interface FeedReader
{
public boolean read();
public void setFeedHandler(FeedHandler handler);
}
public interface FeedHandler
{
public void processEntry(FeedEntry entry);
}
64. Example: Reading RSS
AbstractFeedReader acts as a superclass for
concrete reader classes
– Layered Supertype pattern
public abstract class AbstractFeedReader implements FeedReader
{
protected FeedHandler feedHandler;
public void setFeedHandler(FeedHandler handler)
{
this.feedHandler = handler;
}
public abstract boolean read();
}
65. Example: Reading RSS
RssFeedReader
public class RssFeedReader extends AbstractFeedReader
{
private String source;
public RssFeedReader(String source)
{
this.source = source;
}
public boolean read()
{
// reading ...
feedHandler.processEntry(new FeedEntry(ent.getTitle(),
ent.getLink(), ent.getPublishedDate().toString()));
}
return true;
}
66. Example: Reading RSS
ReaderProcess is the client
public class ReaderProcess implements FeedHandler
{
FeedReader reader;
public ReaderProcess()
{
ReaderFactory factory = ReaderFactory.getReaderFactory();
reader = factory.getFeedReader("http://...");
reader.setFeedHandler(this);
}
public void processEntry(FeedEntry entry)
{
...
}
}
68. Call-back Handlers
Inverting the Dependency
– Let a class call you back
Example
– sort routine, reading records
ReaderProcess RssFeedReader
processEntry
processEntry
processEntry
Read
69. Creating objects
Program to an implementation
Program to interface/subtype
Program to unknown creation
Dog d = new Dog();
d.bark();
Animal animal = new Dog();
animal.makeSound();
Animal animal = getAnimal();
animal.makeSound();
Code smell!
70. The Problem with “new”
new is used to create object
Problem is this:
– Even if we use supertypes (interfaces or abstract
classes) we have to have concrete class behind it
– This violates the Program to Interfaces Design
Principle
– The code also violates the Open Closed Principle
Animal animal = new Dog();
animal.makeSound();
71. Program to an interfaces
Dependency Injection
– Make the caller responsible for setting the dependency
private Animal animal;
public setAnimal(Animal animal)
{
this.animal = animal;
}
...
animal.makeSound();
Injection
happens
here, in the
set-method
LOOSE COUPLING = BEAUTIFUL!
72. Program to unknown creation
What does this mean?
Animal animal = getAnimal();
animal.makeSound();
Where is this
getAnimal
coming from?
74. FeedReader
Objects are created with new
public class ReaderProcess
{
FeedReader reader;
public ReaderProcess()
{
reader = new RssFeedReader
("http://www.mbl.is/mm/rss/togt.xml");
}
Holy Cow!
new creates
concrete object
not abstraction!!
75. FeedReader
We need to have diffrent types
public ReaderProcess(String type, String source)
{
if(type.equals("rss"))
reader = new RssFeedReader(source);
else if (type.equals("atom"))
reader = new AtomFeedReader(source);
else if (type.equals("xml"))
reader = new XmlFeedReader(source);
reader.setFeedHandler(this);
}
Holy Macaroni!
This smells!!!
Violates the OCP
76. Moving the Dependency
The name of the class is put in to a properties
file
– ReaderFactory has no clue of what class it is
– It just has to be a subclass of FeedReaderpublic static FeedReader getFeedReader()
{
FeedProperties prop = new FeedProperties();
Class instanceClass;
FeedReader reader = null;
try {
instanceClass = Class.forName(prop.getProperty("reader"));
reader = (FeedReader)instanceClass.newInstance();
}
catch (Exception e) {
System.out.println("loading class failed");
return null;
}
reader.setSource(prop.getSource());
return reader;
}