meeting -*- Outline -*- ** Strategy (23.6) how to deal with complex pricing logic, such as special fares for: - buying tickets via the Internet - flights to a particular city - flights through a particular city - package deals, - senior citizen discounts etc. the problem is - we don't want to have to rewrite the program every time a new pricing strategy is designed. - We can't anticipate all the strategies that might be dreamed up in the future See Gamma et al, pp. 315ff ------------------------------------------ STRATEGY (23.6, GoF, p. 315ff) Problem: How to allow related algorithms to vary independently from clients that use them? How to support "pluggable" code? How to hide data needed by algorithms from clients. How to avoid lots of conditional logic to select algorithms. Solution: Define each algorithm in a separate class, with a common interface. Document the common specification in the interface, but use underspecification, to allow for the variation. Example: Airline pricing schemes ------------------------------------------ Context: Reservations have a need to use a pricing strategy The Reservation has an attribute which is a PricingStrategy object, this object is used to discount the price, based on various deals (e.g., flying through Detroit). ------------------------------------------ BACKGROUND |---------------------------------------| | Reservation | |---------------------------------------| | pricingStrategy: IPricingStrategy | | flights: List of Flight | | | |---------------------------------------| | getTotal(): Money | | getPreDiscountTotal() : Money | | | |---------------------------------------| public class Reservation { public Money getTotal() { return pricingStrategy.getTotal(this); } public Money getPreDiscountTotal() { Iterator i = flights.iterator(); Money tot = new Money(); while (i.hasNext()) { Flight f = (Flight) i.next(); tot = tot.add(f.getTotal()); } return tot; } ------------------------------------------ Draw a collaboration diagram in Fig 23.9 (Reservation replaces Sale) |--------| t := getTotal()|--------------| 1.1.1*:s:=getTotal() |---------|| ________________|r:Reservation |----------------------| :Flight |- |--------------| |---------| | | | 1: t := getTotal(r) v | 1.1: t := | O getPreDiscountTotal() | IPricingStrategy ^ | | | |-------------| | :Object | |-------------| ------------------------------------------ THE STRATEGY PART |--------------------------------------| | <> | | IPricingStrategy | |--------------------------------------| |--------------------------------------| | getTotal(context:Reservation): Money | |--------------------------------------| ------------------------------------------ Draw in some sample classes that implement this interface E.g., SaleCityPricingStrategy, SeniorCitizenPricingStrategy *** discussion Q: Where is the pricing strategy work really being done? In subclasses of PricingStrategy **** creation Q: How should the pricing strategy objects be created? use a factory pattern **** data for strategies may want to read from external DB, to make even more flexible *** related patterns Q: What patterns are related? based on Polymorphism, provides protected variation wrt changing algorithms, often created by a factory