GoF Design Patterns
CSC 440: Software Engineering Slide #1 Topics
1. GoF Design Patterns 2. Template Method 3. Strategy 4. Composite 5. Adapter
CSC 440: Software Engineering Slide #2 Design Patterns Book
Classic text that started Design Patterns movement written by the Gang of Four (GoF). We’ll introduce several widely used patterns from the book. Useful solutions for certain problems, but if you don’t have the problem, don’t use the pattern.
CSC 440: Software Engineering Slide #3 GoF Design Patterns Catalog
Behavioral Creational Structural
Interpreter Factory Adapter Template Abstract Factory Bridge method Builder Chain of Composite Responsibility Prototype Decorator Command Singleton Façade Iterator Flyweight Mediator Memento Proxy Observer State Strategy Visitor
CSC 440: Software Engineering Slide #4 GoF and GRASP Patterns
GoF patterns are specializations and/or combinations of the more fundamental GRASP design patterns. Example: Adapter Pattern provides Protected Variations through use of Indirection and Polymorphism
CSC 440: Software Engineering Slide #5 Template Method
Pattern Name: Template Method Problem: How to implement an algorithm that varies in certain circumstances? Solution: Define the skeleton of the algorithm in the superclass, deferring implementation of the individual steps to the subclasses.
CSC 440: Software Engineering Slide #6 Example: The Report Class class Report def output_report(format) if format == :plain puts(“*** #{@title} ***”) elsif format == :html puts(“
”) puts(“CSC 440: Software Engineering Slide #7 Report with Template Method class Report def output_report(format) output_start() output_head() output_body() output_end() end end
CSC 440: Software Engineering Slide #8 HTMLReport class HTMLReport < Report def output_start puts(“html”) end def output_head() puts(“
CSC 440: Software Engineering Slide #9 PlainTextReport
class PlainTextReport < Report def output_start end def output_head() puts(“*** #{@title} ***”) end def output_body() puts(“…”) end def output_end() end end
CSC 440: Software Engineering Slide #10 Strategy
Pattern Name: Strategy Problem: How to design for varying, but related, algorithms or policies without using inheritance? Solution: Write each algorithm in its own class, with a common interface and use algorithm classes via object composition.
CSC 440: Software Engineering Slide #11 Abstract Formatter Class class Formatter def output_report(title, text) raise “Abstract method called.” end end
CSC 440: Software Engineering Slide #12 HTML Formatter Class
class HTMLFormatter < Formatter def output_report(title, text) puts(“) puts(“
CSC 440: Software Engineering Slide #13 PlainText Formatter Class
class PlainTextFormatter < Formatter def output_report(title, text) puts(“*** #{title} ***”) puts(text) end end
CSC 440: Software Engineering Slide #14 POS Strategy Example
How do we handle different sale pricing policies in the POS system? 10% off $10 off if over $200 Solution: Create multiple SalePricingStrategy classes, each with a polymorphic getTotal() method that implements the particular policy described by that class.
CSC 440: Software Engineering Slide #15 Strategy Example
«interface» ISalePricingStrategy
g e tT o ta l( S a le ) : M o n e y
PercentDiscount AbsoluteDiscount ??? PricingStrategy OverThreshold PricingStrategy PricingStrategy percentage : flo a t ... d is c o u n t : M o n e y g e tT o ta l( s :S a le ) : th re s h o ld : M o n e y ... M o n e y g e tT o ta l( s :S a le ) : M o n e y
{ { re tu rn s .getPreDiscountTotal() * percentage p d t := s .getPreDiscountTotal() } if ( p d t < th re s h o ld ) return pdt e ls e return pdt - d is c o u n t } CSC 440: Software Engineering Slide #16 Context Objects
A strategy object is attached to a context object—the object to which it applies its algorithm. In this example, the context object is a Sale. The context object is often passed as an argument to the strategy object as an argument, e.g. self or this. When a getTotal() method is sent to a Sale, it delegates some of the work to its strategy object.
CSC 440: Software Engineering Slide #17 Collaboration of Sale and Strategy Objects
lin e Ite m s [ i ] : :PercentDiscount s : S a le SalesLineItem PricingStrategy
t = g e tT o ta l
{ t = p d t * percentage } s t = getSubtotal lo o p
t = g e tT o ta l( s )
p d t = getPreDiscountTotal note that the Sale s is passed to the Strategy so that it has parameter visibility to it for further collaboration
CSC 440: Software Engineering Slide #18 Collaboration of Sale and Strategy Objects
Sale needs attribute visibility to its Strategy
S a le
«interface» d a te 1 ISalePricingStrategy ...
pricingStrategy g e tT o ta l( S a le ) : M o n e y g e tT o ta l() ...
g e tT o ta l() PercentDiscount AbsoluteDiscount { PricingStrategy OverThreshold ... PricingStrategy return pricingStrategy .g e tT o ta l( th is ) percentage : flo a t d is c o u n t : M o n e y } g e tT o ta l( S a le ) : M o n e y th re s h o ld : M o n e y
g e tT o ta l( S a le ) : M o n e y
CSC 440: Software Engineering Slide #19 Discussion
Strategy provides Protected Variations with respect to changing algorithms. Strategy is a specialization of Polymorphism. Passing the context object as an argument enables easy collaboration and visibility, but it also increases coupling.
CSC 440: Software Engineering Slide #20 Composite Pattern Name: Composite Problem: How to treat a group of objects the same way (polymorphically) as a non-composite (leaf or atomic) object? How to create a tree of objects? Solution: Define classes for composite and leaf objects that implement identical interfaces.
CSC 440: Software Engineering Slide #21 Composite Example
CSC 440: Software Engineering Slide #22 Abstract Component Class class Task def initialize(name) @name = name end def name return @name end def get_time_required return 0.0 end end
CSC 440: Software Engineering Slide #23 Example Leaf Class class MixTask < Task def initialize(name) super(“Mix the batter”) end def get_time_required return 3.0 end end
CSC 440: Software Engineering Slide #24 Example Composite Class class MakeBatterTask < Task def initialize(name) super(“Make batter”) @sub_tasks = Array.new add_sub_task(AddLiquidsTask.new) add_sub_task(MixTask.new) end
def get_time_required time = 0.0 @sub_tasks.each { |t| time += t.get_time_required } return time end end CSC 440: Software Engineering Slide #25 Example Composite Class class MakeBatterTask < Task def add_sub_task(task) @sub_tasks.push(task) end
def remove_sub_task(task) @sub_tasks.delete(task) end end
CSC 440: Software Engineering Slide #26 POS Composite Example
Problem: How do we handle the case of multiple, conflicting pricing policies? 20% senior discount preferred customer discount of 15% of sales over $400 today there is a $50 off purchases over $500 buy 1 case of Darjeeling, get 15% discount off everything
CSC 440: Software Engineering Slide #27 Composite Example
Pricing strategies attach to sale by virtue of: Time period. Customer type. A particular line item. Need to define a conflict resolution strategy. How can we modify design to Sale object doesn’t know if there are one or many pricing strategies and also provide for conflict resolution?
CSC 440: Software Engineering Slide #28 POS Composite Example Add new CompositePricingStrategy class Abstract class. Has two concrete subclasses that provide for different conflict resolution strategies: CompositeBestForCustomerPricingStrategy CompositeBestForStorePricingStrategy Polymorphically provides getTotal() method, so it can be called like any other PricingStrategy. add( PricingStrategy ) method allows set of PricingStrategy objects to be composed together.
CSC 440: Software Engineering Slide #29 { All composites maintain a list of ... contained strategies . T h e re fo re , return pricingStrategy .g e tT o ta l( th is ) define a common superclass Example } CompositePricingStrategy th a t defines this list (n a m e d s tra te g ie s ).
S a le
«interface» d a te 1 ..* 1 ISalePricingStrategy ... pricingStrategy g e tT o ta l( S a le ) : M o n e y s tra te g ie s g e tT o ta l() ...
PercentageDiscount AbsoluteDiscount C o m p o s ite PricingStrategy OverThreshold PricingStrategy PricingStrategy percentage : flo a t d is c o u n t : M o n e y g e tT o ta l( S a le ) : M o n e y th re s h o ld : M o n e y add( ISalePricingStrategy ) g e tT o ta l( S a le ) : M o n e y g e tT o ta l( S a le ) : M o n e y
{ CompositeBestForCustomer CompositeBestForStore return sale .getPreDiscountTotal() * PricingStrategy PricingStrategy percentage }
g e tT o ta l( S a le ) : M o n e y g e tT o ta l( S a le ) : M o n e y
{ lowestTotal = INTEGER .MAX for each ISalePricingStrategy strat in pricingStrategies { to ta l := s tra t.g e tT o ta l( s a le ) lowestTotal = m in ( to ta l, lowestTotal ) } return lowestTotal } CSC 440: Software Engineering Slide #30 POS Composite Sequence
UML : ISalePricingStrategy is an interface , not a class ; this is the way in UML 2 to indicate an object of an unknown class , but that implements this interface
lin e Ite m s [ i ] : :CompositeBestForCustomer s tra te g ie s [ j ] : s : S a le SalesLineItem PricingStrategy : ISalePricingStrategy
t = g e tT o ta l
s t = getSubtotal lo o p
t = g e tT o ta l( s )
{ t = m in (set of all x ) } lo o p x = g e tT o ta l( s )
th e S a le object treats a Composite Strategy that contains other strategies just like any other ISalePricingStrategy
CSC 440: Software Engineering Slide #31 Discussion
Core of Composite pattern is: Outer composite object contains a list of inner objects. Both inner and outer objects implement the same interface. Sale object cannot distinguish whether it’s using an atomic or composite PricingStrategy object.
CSC 440: Software Engineering Slide #32 Adapter Pattern Name: Adapter Problem: How to resolve incompatible interfaces, or provide a stable interface to similar components with different interfaces? Solution: Convert the original interface of a component into another interface, through an intermediate adapter object.
CSC 440: Software Engineering Slide #33 Adapter Example Class Diagrams
«interface» Adapters use interfaces and ITaxCalculatorAdapter polymorphism to add a level of indirection to varying APIs in other g e tT a x e s ( S a le ) : List of TaxLineItems c o m p o n e n ts .
TaxMasterAdapter GoodAsGoldTaxPro A d a p te r
g e tT a x e s ( S a le ) : List of TaxLineItems g e tT a x e s ( S a le ) : List of TaxLineItems
«interface» «interface» IAccountingAdapter ICreditAuthorizationService A d a p te r postReceivable ( CreditPayment ) p o s tS a le ( S a le ) requestApproval(CreditPayment,T e rm in a lID , M e rc h a n tID ) ......
«interface» IInventoryAdapter SAPAccountingAdapter GreatNorthernAccountingAdapter ...
postReceivable ( CreditPayment ) postReceivable ( CreditPayment ) p o s tS a le ( S a le ) p o s tS a le ( S a le ) ...... Adapter Example Sequence Diagram
:R e g is te r : SAPAccountingAdapter
makePayment ... S O A P o v e r HTTP
p o s tS a le ( s a le ) xxx « a c to r» : S A P S y s te m
the Adapter adapts to interfaces in other components
CSC 440: Software Engineering Slide #35 Updating the Domain Model
Adapter design introduced a new domain ... S a le concept: the TaxLineItem 1 ... d a te
tim e Discovery of new domain C o n ta in s concepts is natural in an 1 C o n ta in s ... iterative process. 1 ..* 1 ..* ... S a le s T a x Update Domain Model L in e Ite m L in e Ite m
only if you will be using it q u a n tity description p e rc e n ta g e in future iterations. a m o u n t
CSC 440: Software Engineering Slide #36 References 1. Gamma, Helm, Johnson, Vlissides, Design Patterns, Addison-Wesley, 1994. 2. Craig Larman, Applying UML and Patterns, Third Edition, Prentice Hall, 2005. 3. Russ Olsen, Design Patterns in Ruby, Addison- Wesley, 2008. 4. Shalloway and Trott, Design Patterns Explained, Second Edition, 2005.
CSC 440: Software Engineering Slide #37