Upload
olafur-andri-ragnarsson
View
790
Download
0
Embed Size (px)
Citation preview
HÖNNUN OG SMÍÐI HUGBÚNAÐAR 2015L05 DESIGN PATTERNS
Agenda
PatternsThe Observer PatternThe Open-Closed PrincipleCallback HandlersBase Patterns
ReadingImportance of Design Patterns and Frameworks for Software Development Design PatternsObserver patternFactory pattern
Catalog of Patterns of Enterprise Application Architecture: Gateway, Mapper, Layer Supertype, Separated Interface Registry, Value Object, Money, Plugin, Service Stub
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
Design Patterns
Patterns originated as an architectural concept (as in building houses)
History
“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
Landmark book from 1995: Design Patterns: Elements of Reusable Object-Oriented Software
History
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
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
Vintage Design Patterns
Dr. Heinz Kabutz (http://www.javaspecialists.co.za)
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
Enterprise Patterns Classification▪ Domain Logic Patterns▪ Data Source Architectural Patterns▪ Object-Relational Behavioural Patterns▪ Object-Relational Structural Patterns▪ Object-Relational Metadata Mapping Patterns▪ Web Presentation Patterns▪ Distribution Patterns▪ Offline Concurrency Patterns▪ Session State Patterns▪ Base Patterns
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
Structure of Patterns
▪ Name▪ The Intent▪ The Sketch▪ Motivation▪ How it Works▪ When to Use it▪ Further Reading▪ Examples
There are many ways to structure patterns – this is one, and it is similar to all others
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
▪ 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
The Intent
▪ Visual representation of the pattern, often but not always a UML diagram
▪ Plug-in
The Sketch
Domain Object <interface> ID Generator
Some Class
ImplementsUses
▪ Description of a motivating problem for the pattern– Problem description– May not be the only problem for the pattern
Layer supertype
Motivation
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 behaviour into a common Layer Supertype
▪ Describes the solution– Implementation Issues and variations– Independent of any particular platform– Platform dependent sections are identified– UML Diagrams if applicable
How it Works
Caller a plugin factorya plugin
configuration
getPlugin
lookupPluginByType
new plugin
▪ 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
When to Use it
▪ 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; }
Example
Layered Supertype example
▪ 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
Using Design 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
Problems with Design Patterns
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
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.
Sale Server Bingo
Publish and subscribe
Sale Server Bingo
registerObserver
notify
notify
ObserverSubject
The Observer Pattern
Weather Monitoring ExampleWeather monitoring System has be set up
Humidity sensor
Temperature sensor
Pressure sensor
WeatherStation
WeatherData Object
Sale Server
Current conditions:Temp: 15℃ Humidity: 60 Pressure: ▽
DisplayUpdate display
Pull data
measurementsChanged
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
The Weather Monitoring ExampleWeatherData 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); } ... }
▪ Based on our first implementation, which of the following apply
A) We are coding to concrete implementation not abstractionsB) For every new display element we need to alter codeC) We have no way to add (or remove) display elements at runtimeD) The display elements don’t implement a common interfaceE) We have not encapsulated the part that changesF) We are violating encapsulation of the WeatherData class
QUIZ
The Weather Monitoring ExampleWeatherData 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 concrete implementation we have no way to add or remove
displays without code changeViolates OPEN-CLODED PRINCIPLE
Area of change. We need to encapsulate this
At least a common interface
Pattern: ObserverOne or more observers or listeners are registered to
observe an event which may be raised by the observed object (the subject)
Sometimes called publish/subscribeSimilar to call-back handlersOne-to-Many relationship
BenefitsListening object gets information when neededSubject does not become dependent on multiple observers
Observer
<interface> Observer
Notify()
<interface> Subject
registerObserver(Observer)
UnregisterObserver(Observer)
NotifyObservers()
NotifyObservers() { for(Observer o : observerList) o.notify() }
ConcreteObserverA
notify()
ConcreteObserverA
notify()
ObserverList
Loose CouplingWhen two object are loosley coupled, the can interact but they have very little knowledge of each other
The Observer Pattern loosely 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
Loosely Coupled Principle
Strive for loosely coupled designs between objects that interact
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); }
The Weather Monitoring 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); }
POLYMORPISHM
The Weather Monitoring 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(); }
POLYMORPISHM
The Weather Monitoring 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
The Weather Monitoring 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%
The Weather Monitoring Example
▪ When two object are loosely coupled, the can interact but they have very little knowledge of each other
▪ The Observer Pattern loosely coupled design– The only thing the subject knows about observer is that it
implements a certain 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
Loose Coupling
The Open-Closed Principle
The Open-Closed Principle
Software entities like classes, modules and functions should be open for extension but closed for modifications
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
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; } ...
Holy Buckets!!I need to change the class for new types!!! Horrible!
Resource Allocator Example
Resource Allocator Example
List resources = new ArrayList(); ... public int allocate(intresourceType) { int resourceId = findFreeResource(resourceType); markAsBusy(resourceId); return resourceId; }
Design for extensions
Another Example: Actual Running CodeActual Running Code
protected String normalize(char cCharacter) { switch(cCharacter) { case '<': return "<"; case '>': return ">"; case '&’: return "&"; case '"’: return """; default: return ""+cCharacter; } }
What could possibly be wrong withthis code?
This is not complete This is common problem – a library must existsIf making it yourself, a Map would be better
Callback Handlers
Task
We need to create program that reads feedsFeed can be RSS news, XML or what ever
The program must be loosely coupledNew feed types will come
CustomisationCustomisation
Designing the Reader ApplicationWho creates the objects and where does the creation take place?
EnterpriseApplication
Process FeedsCustomisation
RSS
This stays the same This is what is added
Inverting the dependency: call an interface and let the implementationclass call you back using your interface
CustomisationCustomisation
ReaderProcess
read() processEntry() processEntry() processEntry()
RssFeedReader
read() { …. processEntry() }
This stays the same This is what is added
Examples: reading, sorting…
Designing the Reader Application
public interface FeedReader { public boolean read(); public void setFeedHandler(FeedHandler handler); }
public interface FeedHandler { public void processEntry(FeedEntry entry); }
Process to read an RSS feed• The FeedReader interface defines the role of such readers• Concrete readers must implement read and accept a call-back
handler to get the results back• Pattern Separated Interface
Example: Reading RSS
public abstract class AbstractFeedReader implements FeedReader { protected FeedHandler feedHandler; public void setFeedHandler(FeedHandler handler) { this.feedHandler = handler; } public abstract boolean read(); }
Example: Reading RSSAbstractFeedReader acts as a superclass for concrete reader classes Layer Supertype pattern
This part is required by all feed reader classes
This part must be implemented by some specific reader type
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; } }
Example: Reading RSSRssFeedReader is the specific reader type, in this case RSS
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) { ... } }
Example: Reading RSSReaderProcess is the client or assembler
Example: Reading RSS
Inverting the dependency: call an interface and let the implementationclass call you back using your interface
CustomisationCustomisation
ReaderProcess
read() processEntry() processEntry() processEntry()
RssFeedReader
read() { …. processEntry() }
This stays the same This is what is added
Examples: reading, sorting…
Designing the Reader Application
Factory
Operator new is used to create objectProblem is this:
The Problem with “new”
Even if we use supertypes (interfaces or abstract classes) we have to have concrete class behind it
This violates the Program to Interfaces Design PrincipleThe code also violates the Open Closed Principle
Animal animal = new Dog(); animal.makeSound();
Dependency InjectionMake the caller responsible for setting the dependency
Program to an interfaces
private Animal animal;
public setAnimal(Animal animal) { this.animal = animal; } ...
animal.makeSound();
Injection happens here, in the set-method
LOOSE COUPLING = BEAUTIFUL!
What does this mean?Program to unknown creation
Where did this getAnimal come from?
Animal animal = getAnimal(); animal.makeSound();
What does this mean?FeedReader
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!!
Ok, we´ll just fix this for each theFeedReader
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
The name of the class is put in to a properties fileReaderFactory has no clue of what class it isIt just has to be a subclass of FeedReader
Moving the Dependency
public 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; } Plugin pattern
Properties classLoading Properties
public class FeedProperties extends Properties { protected String reader; protected String source; protected String DEFAULT_PROPERTIES = "feeds.properties";
public FeedProperties() { try { load(new FileInputStream(new File(DEFAULT_PROPERTIES))); reader = getProperty("reader"); source = getProperty("source"); } catch (Exception e) { System.out.println("Loading properties failed"); } } reader=is.ru.honn.feeds.rss.RssFeedReader
source=http://www.mbl.is/mm/rss/togt.xml
Base Patterns
Base Patterns▪ Gateway▪ Mapper▪ Layer Supertype▪ Separated Interface▪ Registry▪ Value Object▪ Plugin▪ Service Stub
Pattern: GatewayAn object that encapsulates access to an external system
or resource
Wrap external APIs into an interfaceAPI is usually for accessing some external resourceExamples: JDBC, JDom, financial software
Customer
Lease
Asset
Pricing Gateway Pricing Package
How It Works• Create a simple API and use it access the
external API through a Gateway• All access is easily defined• Change in the resource does not require
changes in the client software• Gateways should be simple – complex logic
should not be in the clients of the Gateway• Gateways can be generated
Pattern: Gateway
When to Use It• Gateway is useful when accessing external
service• Can be applied with Service Stub• Clear benefit is that is makes it easy to swap
out one kind of resource for another
Pattern: Gateway
Pattern: MapperAn object that sets up communiction between two
independent objects
Create communication between two systems but you still need to make them independent
Customer
Lease
Asset
Pricing Mapper Pricing Package
How it Works• A Mapper is an insulating layer between subsystems• It controls the details of communication between them
without either subsystem being aware of it• Mappers are fairly easy as they are well-defined• The tricky part is what system invokes them – third party
system or make the Mapper an Observer
When to Use it• When you want to decouple different parts of a system
Pattern: Mapper
Pattern: Layer SupertypeA type that acts as the supertype
for all types in its layer
Super class that contains common functionality in a layer
How it works•Use this pattern when you have common features from all objects in a layer
Shape
int x int y Color color
Rectangle Circle Line
When to Use it• When you have common features from all objects
in a layer
Example• Domain objects can
have a common superclass for ID handling
Pattern: Layer Supertype
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; }
Shape class revisited
All objects in the drawing layer must have an origin (x and y) and implement Drawable
public abstract class Shape implements Drawable { protected int x,y; }
Pattern: Layer Supertype
Pattern: Separated InterfaceDefines an interface in a separate package from its implementation
Decouples parts of a system• Controls the dependencies between packages• Implementation can easily be changed
How it works• Interface and implementation is placed in separate
packages• Client uses the interface• Implementation can be determined at configuration time
Layered System• Domain layer depends on Data Source layer• Data Source layer cannot access Domain layer
Pattern: Separated Interface
Data Source Layer
Domain Layer
JDBC Code
Interface RowCallBackHandler
processRow(ResultSet rs)
Concreate class RowCallBackHandler
processRow(ResultSet rs)
implements
Code reading SQL
Execution calls
Separated interface
Pattern: Separated Interface
Pattern: Separated InterfaceInstantiating the implementation• User of the interface should not know the implementation
Solutions• Use a Factory and Plugin method• Use Dependency Injection
public interface FeedHandler { public void processObject (FeedEntry entry); }
public class ReaderClient implements FeedHandler { ... public ReaderClient() { FeedReader reader = ReaderFactory.getFeedReader(); reader.setFeedHandler(this); reader.read("http://rss.news.yahoo.com/rss/tech"); }
public void processObject(FeedEntry entry) { System.out.println(entry); } }
Pattern: Separated Interface
Pattern: RegistryA well-known object that other objects can use to find
common objects and services
A registry is a global object
How It Works• Object that can easily be accessed at any time• Only one object available at any time• Provides services or information• Can have different scopes• Usually not mutable data• Example: System Settings, Loggers
Only one instance running
When to Use it• As a last resort - sell any grandparent before using it
Pattern: Registry
public class Registry { private static Registry soleInstance = new Registry();
public static Registry getInstance() { return soleInstance; }
private Registry() { } ... }
Registry registry = Registry.getInstance(); //registry = new Registry (); Does not work
Pattern: Value ObjectA small simple object, like money or date
range, whose equality isn’t based on identity
Small and easily created objects that hold and represent some dataHow it works• Not based on identity• Equality is based on comparing values of the object• Can be immutable (example is the Date class)When to use it• When you’re basing equality on something other than
identify
class Money...
private long amount; private Currency currency;
public Money(double amount, Currency currency) { this.currency = currency; this.amount = Math.round(amount * centFactor()); } ...
Pattern: Value ObjectExamplesDate, Money
GregorianCalendar cal = new GregorianCalendar();
cal.set(1865, Calendar.APRIL, 14); Date d1 = cal.getTime(); cal.set(1963, Calendar.NOVEMBER, 22); Date d2 = cal.getTime();
System.out.println(d1.equals(d2));
cal.set(1756, Calendar.JANUARY, 27); Date d3 = cal.getTime(); Date d4 = cal.getTime();
System.out.println(d3.equals(d4));
false true
Pattern: Value Object
Pattern: PluginLinks classes during configuration
rather than compilationUse plugin to provide specific implantation• Plugins implement specific interface use by the client
application code• Decision at configuration time or run time• Use factory to load in the plugin
Domain Object <interface> ID Generator
Some Class
ImplementsUses
A caller obtains a Plugin implementation of a separated interface
When to Use It• Use plugin when you have behavior that requires different
implementations based on runtime environment
Pattern: Plugin
Caller a plugin factorya plugin
configuration
getPlugin
lookupPluginByType
new plugin
ReaderClient uses ReaderFactory to get an interface to FeedReader
When to Use It• Use plugin when you have behavior that requires different
implementations based on runtime environment
Pattern: Plugin
Caller a plugin factorya plugin
configuration
getPlugin
lookupPluginByType
new plugin
public ReaderClient() { FeedReader reader = ReaderFactory.getFeedReader(); ... }
public class ReaderFactory { public static FeedReader getFeedReader() { ... try { props.load(new FileInputStream(new File("reader.properties"))); instanceClass = Class.forName(props.getProperty("reader")); reader = (FeedReader)instanceClass.newInstance(); } ... return reader; } }
reader=RssFeedReader
Pattern: Plugin
Pattern: Service StubRemoves dependence upon problematic services
during testingEnterprise systems often need to access external system• Can be out of developers control
Charge generator
<interface> Tax Service
WSDL Tax Service
getTaxInfo
getTaxInfoInternet
class Tax Service
getTaxInfo
Service stub provides implementation for development and testing purposes• Runs locally and in-memory• Implements the same interface of the gateway used to
access the real serviceWhen to Use It• Service stub is useful when dependence on a particular
service is hindering development or testing• Called “Mock Object” in the extreme programming world
Pattern: Service Stub
public class ReaderStub extends AbstractFeedReader { public void read(String url) { feedHandler.processEntry(new FeedEntry("title1", "Bla bla bla")); feedHandler.processEntry(new FeedEntry("title2", "Bla bla bla")); feedHandler.processEntry(new FeedEntry("title3", "Bla bla bla")); } }
title1 Bla bla bla title2 Bla bla bla title3 Bla bla bla
reader=ReaderStub
reader.properties
Pattern: Service Stub
Summary▪ Base Patterns– Gateway, Mapper, Layerd Supertype, Separated Interface,
Registry, Value Object, Plugin, Service Stub, Record Set
▪ Next: From Problem to Patterns– Using design patterns
You use this patterns when you need to break a dependency between two parts of the system
A) RegistryB) GatewayC) Separated InterfaceD) Plugin
QUIZ
Intent of a pattern is this: An object that sets up communication between two objects
A) GatewayB) MapperC) RegistryD) Value Object
QUIZ
Sketch of a pattern is this
A) PluginB) MapperC) RegistryD) Service Stub
QUIZ
Domain Object <interface> ID Generator
Some Class
ImplementsUses
Use this pattern when you find that dependence on a particular service is hindering your development and testing
A) MapperB) Record SetC) Service StubD) Gateway
QUIZ
Using Design Patterns
Next