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) 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, draw a class diagram like figure 23.8 (Reservation replaces Sale) 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). Draw a collaboration diagram in Fig 23.9 (Reservation replaces Sale) ------------------------------------------ CONTEXT OBJECT HEADER // $RCSfile: Reservation.h,v $ #ifndef Reservation_h #define Reservation_h #include "Money.h" class PricingStrategy; class Reservation { public: // ... virtual Money *getTotal(); virtual Money *getPreDiscountTotal(); private: PricingStrategy *pricingStrategy; }; #endif ------------------------------------------ ------------------------------------------ CONTEXT OBJECT IMPLEMENTATION // $RCSfile: Reservation.cpp,v $ #include "Reservation.h" #include "PricingStrategy.h" long Reservation::pennies() { return getTotal()->pennies(); } const char* Reservation::description() { return "a reservation"; } Money * Reservation::getTotal() { return pricingStrategy->getTotal(this); } Money *Reservation::getPreDiscountTotal(){ vector::iterator i; Money *tot = new Money(); i = flights->begin(); for (; i != 0; i++) { tot = *tot + *((*i)->getTotal()); } return tot; } ------------------------------------------ ------------------------------------------ STRATEGY INTERFACE HEADER // $RCSfile: PricingStrategy.h,v $ #ifndef PricingStrategy_h #define PricingStrategy_h #include "Money.h" #include "Reservation.h" class PricingStrategy { public: virtual Money * getTotal(Reservation *context) = 0; virtual ~PricingStrategy() = 0; protected: Reservation *reservation; }; #endif ------------------------------------------ ------------------------------------------ STRATEGY INTERFACE IMPLEMENATION // $RCSfile: PricingStrategy.cpp,v $ #include "PricingStrategy.h" ------------------------------------------ *** 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