Title: Presentation 16 the final one
1CSC 335 Object-Oriented Programming and Design
Presentation 16 the final one Pattern-Oriented
Design Design Patterns Explained A New
Perspective on Object-Oriented Design Alan
Shalloway, James R. Trott Addison Wesley ISBN
0-201-71594-5
2Design patterns weve seen
- Iterator Provide a way to access the elements of
a collection sequentially without exposing
underlying representation Iterator,
ListIterator, Enumeration - Strategy define a family of algorithms,
encapsu-late each one, and make them
interchangeable diceRerollStrategy, Layout
Managers - Composite Lets clients treat individual objects
and compositions of object uniformly java.io,
JPanel
3Design patterns weve seen
- Observer Define a 1 to many relationship so when
one object changes state, all dependents are
notified and updated automatically. Add
functionality by attaching other observers
Windows Explorer - Mediator Define an object that encapsulates how a
set of objects interact while promoting loose
coupling between those objects Controllers - Decorator Attach additional responsibilities to
an object dynamically. Provides a flexible
alternative to subclassing java.io streams
4Design patterns weve seen
- Factory Define a way to instantiate classes and
make another class be responsible for
instantiating classes. The class may use
arguments or state to determine which is
appropriate Marty's sound factory,
NumberFormat.getCurrencyInstance - Singleton Ensure a class has only one instance
and provide a global point of access to it
5More Design Patterns
- There are 16 other OO design patterns cataloged
in the GoF book (weve seen 8 of 23) - We'll now consider how to use some of these
design patterns when designing a system - The new case study is in electronic retailing
over the internet (An Ecommerce system) - Several design decisions will be aided by
knowledge of existing design patterns - at a fairly high level of abstraction
6Plan too much, plan ahead, or dont plan at all?
- Development of software systems can suffer from
analysis paralysis attempt to consider all
possible changes in the future - At other times developers jump to code too
quickly - there is tremendous pressure to deliver, not
maintain - Lifes three certainties for software developers
- Death, Taxes, and Changes in Requirements
- There is a middle ground for planning for change
7How will change occur
- First, anticipate that changes will occur
- Consider where they will change, rather than the
exact nature of the changes - These issues will come up in the ecommerce case
study
8Principles of Good Design
- Some guiding principles from GoF
- Program to an interface, not an implementation
- Commit to using an interface rather than a
concrete class - Favor object composition over inheritance
- Ideally you create new functionality only by
combining existing objects - Inheritance may play a role, but it is overused,
try for object composition - Consider what is variable in your design
9What is variable in the design?
- Instead of focusing on what might force a change
to your design - Consider what you might want to change
- Encapsulate the concept that varies
- a theme of many design patterns
- Hopefully there are long term benefits without a
lot of extra work up front
10OO Design Patterns Used
- In the upcoming case study, these design patterns
will help make for a system that is good design - Strategy
- Singleton
- Decorator
- Observer
- We've considered all four
11An Ecommerce System
- There is a controller object that handles sales
request over the internet - When the sales order is requested, the controller
delegates to a SalesOrder object
12Assign Responsibilities
- SalesOrder responsibilities
- Allow users to make an order with a GUI
- Process the order
- Print a sales receipt
13Changing Requirements
- Start charging taxes on order from customers
- need to add rules for taxation, but how?
- modify existing SalesOrder to handle U.S. taxes
- extend the existing SalesOrder object and modify
the tax rules so it applies to the new country - This is an inheritance solution
14Subclassing Solution
TaskController
SalesOrder
SalesTicketPrinter
calcTax()double
US Tax
Rules
Canadian
Tax Rules
CanadianSalesOrder
calcTax()double
15Favor Composition Over Inheritance
- Design pattern theme of composition over
inheritance is ignored in previous design - Here is a different approach
- consider what is variable in the design
- encapsulate the concept the varies
- Accept the fact that tax rules vary country to
country and state to state and county to county,
and city to city and they change quite often
16Alternate Designs
- Another design is to use an abstract class with
an interface (calcTax) and develop a hierarchy - In Java, we can design an interface and contain a
reference to an object the implements the
interface - What is the Pattern Name? _____________ ?
- public interface TaxCalculator
- // Salable objects know price and how taxed
- public double taxAmount(Salable itemSold,
- double quantity)
-
17A Better Design with Strategy
18Why doe Strategy make this design better?
- Better Cohesion
- sales tax details are in its own class
- Easy to add tax rules from different countries
- Easier to shift responsibilities
- In the first design (with CanadianSalesOrder
extending USSalesOrder), only TaskController
could determine which type of sales order to use - In the current design, either TaskController or
SalesOrder could set the TaxCalculator
19Determine What Varies
- What Varies?
- The business rules for taxation
- Current design handles variations at least as
well as the other design design - Current design will handle future variations as
well - A family of tax calculation algorithms have been
encapsulated as objects, they are
interchangeable, this is the Strategy pattern
applied in our Ecommerce system
20Using the Strategy Pattern
- What happens when EnglishTaxer is added
- In England, old-age pensioners are not required
to pay taxes on sales items - How can this be handled?
- 1) Pass age of the Customer to TaxCalculator
object - 2) Be more general and pass the Customer object
- 3) Be even more general and pass a reference to
the SalesOrder object (this) to the TaxCalculator
and let that Strategy object ask SalesOrder for
customer age
21Is this change bad?
- To handle this new requirement, SalesOrder and
TaxCalculator have to be modified - But the change is small and certainly doable
- Not likely to cause a new problem
- If the Strategy needs more information, pass the
information to the object as an argument - Strategy can be applied anywhere you hear this
- "At different times, different business rules
apply"
22Singleton Pattern
- Singleton Ensure a class only has one instance
and provide a global point of access to it - The singleton pattern works by having a special
method that is used to instantiate the object - when called, the method checks to see if the
object has already been instantiated - it returns the singleton if instantiated or
constructs a new one if this is the first call to
get the instance - to guarantee this, have a private constructor
23Using Singleton
- TaxCalculators are currently encapsulated as
Strategy objects - How many USTaxer objects are required in this
system? How many CanadianTaxers? - Forces
- The same object is being used over and over again
- More efficient to avoid instantiating them and
throwing them away again and again - Doing all at once could be slow to start up
- Could instantiate these objects as needed
24Only want one when needed
- Dont need more than one instance of each
TaxCalculator class - Solution
- Let Strategy objects handle the instantiation
- Let there be only one instance
- Dont concern clients (SalesOrder) over this
detail - Use the Singleton Pattern
25USTaxer is now a Singleton
- public class USTaxer implements TaxCalculator
-
- private static USTaxer instance // Only one
- private static double taxRate
- private USTaxer()
- taxRate 0.06 // greatly simplified
-
- public static USTaxer getInstance()
- if( instance null )
- instance new USTaxer()
- return instance
-
- public double taxAmount(Salable item, double
quant) - return 0.00 // TBA
-
26(No Transcript)
27Class constructs the singleton
- Singleton is one of the creational patterns
- TaxCalculator taxer null
-
- for (int j 0 j lt 100 j)
- taxer USTaxer.getInstance()
- // There is only one instance of USTaxer
- // The following code would show that tax
someone - // in the US must pay for one Salable item
- System.out.print(taxer.taxAmount(new Salable(),
1))
28Other Patterns applied
- In the Ecommerce system, we will now
- Decorate a SalesTicket and
- Observe a Customer
- Current design of this system is shown on the
next slide with the CanadianTaxer as a Singleton - However, it doesn't have the Customer yet
29dependency
aggregation (Salable is one part of SalesOrder)
composition
implements
30Review Aggregation / Composition
- Definitions from the Unified Modeling Language
Guide - Aggregation A special for of association that
specifies a whole/part relationship between the
aggregate (the whole) and a component (the part) - Composition A form of aggregation with strong
ownership. Once a component is created, its lives
and dies with its whole - A TaxCalculator object is only necessary with a
SalesOrder not used elsewhere
31Decorate SalesTicketPrinter
- Assume the SalesTicketPrinter currently creates
an html sales receipt Airline Ticket - New Requirement Add header with company name,
add footer that is an advertisement, during the
holidays add holiday relevant header(s) and
footer(s), were not sure how many - One solution
- Place control in SalesTicketPrinter
- Then you need flags to control what header(s) get
printed
32One Solution
- This works well if there are few header and
footer options or perhaps just add a few private
helper methods to
underline indicates static methods
33Strategy Pattern?
- If there are many types of headers and footers,
with only one being printed each time, use
Strategy - If there are more than one header and footer, and
the ordering changes, and the number of
combinations grows - Use the Decorator design pattern to chain
together the desired functionality in the correct
order needed
34Decorator Again
- Decorator summary repeated Attach additional
Responsibilities to an object dynamically. - Decorators provide a flexible alternative to
subclassing for functionality GoF - Start chain with decorators, end with original
object
Decorator 1
Decorator 2
Concrete Component
Example keyboard new BufferedReader(
new InputStreamReader(
System.in))
35(No Transcript)
36A Simple SalesTicket Mammal
- // Instances of this class are the sales tickets
- // that may be decorated
- public class SalesTicket extends Component
-
- public void printTicket()
- // Hard coded here, but simpler than
- // adding a new Customer class now
- System.out.println("Customer Bob")
- System.out.println("The sales ticket
itself") - System.out.println("Total 123.45")
-
-
37TicketDecorator
- public abstract class TicketDecorator extends
Component -
- private Component myComponent
- public TicketDecorator()
- myComponent null
-
- public TicketDecorator(Component c)
- myComponent c
-
- public void printTicket()
- if(myComponent ! null)
- myComponent.printTicket()
-
38A Header Decorator
- public class HeaderDecorator1 extends
TicketDecorator -
- public HeaderDecorator1(Component c)
- super(c)
-
- public void printTicket()
- this.printHeader()
- super.printTicket()
-
- public void printHeader()
-
- System.out.println("_at__at_ Header One _at__at_")
-
39A Footer Decorator like SleepingAnimal
- public class FooterDecorator1 extends
TicketDecorator -
- public FooterDecorator1(Component c)
- super(c)
-
- public void printTicket()
- super.printTicket()
- this.printFooter()
-
- public void printFooter()
- System.out.println(" FOOTER two ")
-
-
40SalesOrder a client
- public class SalesOrder
-
- public static void main(String args)
-
- SalesOrder s new SalesOrder()
- s.printTicket()
-
- public void printTicket()
- // Get an object decorated dynamically
- Component myST Configuration.getSalesTicket(
) - myST.printTicket()
-
- // calcSalesTax ...
41Simple Configuration
- // This object would determine how to decorate
the - // SalesTicket. This could become a Factory
- public class Configuration
-
- public static Component getSalesTicket()
- // Return a decorated SalesTicket
- return
- new HeaderDecorator1(
- new HeaderDecorator2(
- new FooterDecorator1(
- new FooterDecorator2(
- new SalesTicket() ))))
-
42Output with Current Configuration
- Output
- _at__at_ Header One _at__at_
- gtgt Header Two ltlt
- Customer Bob
- The sales ticket itself
- Total 123.45
- FOOTER two
- FOOTER two
43SalesOrder delegates to Component to print
ticket
The other part of the system
44(No Transcript)
45Observe Customer
- New Requirements Send an email to a new customer
and verify the customer's address with the post
office - If this was it, hard code Customer behavior when
being added to data base
46Or Use Observer
- With additional behaviors (such as send
advertisements via snail mail), there may be a
changing list of objects that need notification
that a new customer is being added - These objects will have different interfaces
- verifyAddress, sendEmail, sendCoupons,
sellInformationToTelemarketers, .... - Let's change all two, or three, or four objects
into "Observers"
47Observer
- Have Customer extends Observable
- Have all of the objects that need notification
implement Observer (all have the update method) - Have some configurer add the correct observers to
the Customer object with addObservers - Have the addCustomer method send the message
notifyObservers
48Design with Observer
49The Decorator Pattern Summary and Another
example
- Intent
- Attach additional responsibilities to an object
dynamically. Decorators provide a flexible
alternative to subclassing for extending
flexibility - Also Known As
- Wrapper
- Motivation
- Want to add properties such as borders or
scrollbars to a GUI component or more methods to
an existing object. - Can be done with inheritance, but this limits
flexibility (couldnt change borders at runtime).
A better way is to use composition.
50Applicability
- Use Decorator
- To add responsibilities to individual objects
dynamically without affecting other objects - When extending classes is impractical
- Sometimes a large number of independent
extensions are possible and would produce an
explosion of subclasses to support every
combination - this approach is shown next
51An Application
- Suppose there is a TextView GUI component and you
want to add different kinds of borders and/or
scrollbars to it - Currently, there are three types of borders
- Plain, 3D, Fancy
- And two scrollbars
- Horizontal and Vertical
- An inheritance solution requires15 classes for
one view
52Thats a lot of classes!
- TextView-Plain
- TextView-Fance
- TextView-3D
- TextView-Horizontal
- TextView-Vertical
- TextView-Horizontal-Vertical
- TextView-Plain-Horizontal
- TextView-Plain-Vertical
- TextView-Plain-Horizontal-Vertical
- TextView-3D-Horizontal
- TextView-3D-Vertical
- TextView-3D-Horizontal-Vertical
- TextView-Fancy-Horizontal
- TextView-Fancy-Vertical
- TextView-Fancy-Horizontal-Vertical
53Disadvantages
- Inheritance solution has an explosion of classes
- If another type of border were added, how many
more classes do we need? - If another view were added, say ImageView or
StreamingVideoView, how many more classes do we
need? - Have to instantiate specific classes at
compiletime - would be better to be able to change borders at
runtime - This is inflexible, cant change view or border
at runtime - Use the Decorator Pattern instead (Java does)
54VisualComponent draw() resize()
Decorator contains a visual component
1
ImageComponent draw() resize()
TextView draw() resize()
Decorator draw() resize()
1
Border draw() resize()
ScrollBar draw() resize()
Fancy draw() resize()
Vert draw() resize()
Plain draw() resize()
3D draw() resize()
Horiz draw() resize()
55Applicability
- The TextView class knows nothing about Borders
and Scrollbars - public class TextView
-
- public void draw()
-
- // Code to draw this Text object
-
-
- public void resize ()
-
- // Code to resize this Text object
-
56Applicability
- The ImageView knows nothing about Borders and
Scrollbars - public class ImageView
-
- public void draw()
-
- // Code to draw this Image Object
-
-
- public void resize ()
-
- // Code to resize this Image Object
-
57Decorators Contain Components
- But the decorators need to know about components
- public class FancyBorder
-
- private Component component
- public FancyBorder(VisualComponent visual)
-
- component visual
-
- public void draw()
-
- component.draw() // forward draw message
contained obj - // Code to draw this FancyBorder object
-
58How to use Decorators
- public class Client
-
- public static void main(String args)
-
- TextView data new TextView()
- Component borderData new FancyBorder(data)
- Component scrolledData new
VertScrollbar(data) - Component borderAndScrolledData
- new HorzScrollbar(borderData)
-
59Motivation Continued
- The more more flexible containment approach
encloses the component in another object that
adds the border - The enclosef object is known as the decoree
- The enclosing object is called the decorator
- The decorator conforms to the interface of the
component so its presence is transparent to
clients - The decorator forwards requests to the component
and may perform additional actions (such as
drawing a Border) before or after any forwarding
60Decorator Pattern in Java
- InputStreamReader
- ... bridge from byte streams to character
streams It reads bytes and translates them into
characters using the specified character
encoding. JavaTMAPI - BufferedReader
- Read text from a character-input stream,
buffering characters so as to provide for the
efficient reading of characters, arrays, and
lines. JavaTMAPI - What programmer's can now code
- BufferedReader keyboard
- new BufferedReader(new InputStreamReader(System.i
n))
61Example of decorator pattern use
BufferedReader decorates InputStreamReader
BufferedReader readLine() ready()
InputStreamReader read() close()
62Java streams
- With gt 60 streams in Java, you can create a wide
variety of input and output streams - this provides flexibility good
- it also adds complexity bad
- Flexibility made possible with inheritance and
classes that accept many different classes that
extend the parameter - You can have an InputStream instance or any
instance of a class that extends InputStream - public InputStreamReader(InputStream in)
63One Constructor for many subclasses
- InputStream has these direct known subclasses
- ByteArrayInputStream, FileInputStream,
FilterInputStream, InputStream,
ObjectInputStream, PipedInputStream,
SequenceInputStream, StringBufferInputStream - System.in is an instance of InputStream
- Check the API
- We decorated a FileInputStream with an
ObjectInputStream so you can read objects that
implement Serializable
64Write text to a text file wrap a file output
stream (for writing to the disk) with a
PrintWriter--that has println
- // You must import java.io.
- PrintWriter outFile null
- try
-
- outFile new PrintWriter (
- new FileOutputStream(filename) )
-
- catch( FileNotFoundException fnfe )
- outFile.println( "Hello world" )
- outFile.close() // do NOT forget this!
- // If you don't close the file, data will be lost!
65(No Transcript)