meeting -*- Outline -*- ** Composite and other design principles (23.7) copy figure 23.14 suppose some customer is: a senior citizen, and thus entitled to a discount, and also is flying through Detroit, and thus entitled to another discount, and the flight has a Saturday night stay which pricing policy should be applied? usually the airline will apply a "best for the customer" (lowest price) conflict resolution strategy, but this is not required, and it could change. so the problem is to: - protect the reservation object from knowledge of the different pricing strategies, and also - to offer a design for conflict resolution ------------------------------------------ COMPOSITE (23.7) Problem: how to treat a group of objects in the same way as a single objects are treated? Solution: Define an interface that both the composite and atomic objects implement. Record the common specification in this interface. Example: ------------------------------------------ |----------------------------| | <> | | SalePricingStrategy | 1..* |----------------------------|<------------| |----------------------------| | pricingStrategies | getTotal(Reservation):Money| | |----------------------------| | ^ ^ ^ | - - - / \- - -| \- - - - - - -| | | | | | 1 |----------------| |----------------| |--------------------------| | SaleCities | | SeniorCitizen | | Composite | | PricingStrategy| | PricingStrategy| | PricingStrategy | |----------------| |----------------| |--------------------------| | cities | | | | | |----------------| |----------------| |--------------------------| | getTotal(...) | | getTotal(...) | | getTotal(...) | |----------------| |----------------| | add(PricingStrategy) | |--------------------------| |------------------^ ^ | | |----------------| |----------------| | BestForCustomer| | BestForCompany | | PricingStrategy| | PricingStrategy| |----------------| |----------------| | | | | |----------------| |----------------| | getTotal(...) | | getTotal(...) | |----------------| |----------------| Note that a CompositePricingStrategy has an attribute "pricingStrategies" which contains the individual pricing strategies that make up the composite. The name of the class CompositePricingStrategy is supposed to be in italics, because it's an abstract class. Show/draw figure 23.14 as well, and note the UML notation there ------------------------------------------ // $RCSfile: CompositePricingStrategy.h,v$ #ifndef CompositePricingStrategy_h #define CompositePricingStrategy_h #include "PricingStrategy.h" #include class CompositePricingStrategy : public PricingStrategy { public: virtual Money * getTotal(Reservation *context) = 0; virtual void add(PricingStrategy *ps); protected: vector * pricingStrategies; }; #endif ------------------------------------------ ------------------------------------------ //$RCSfile:CompositePricingStrategy.cpp,v$ #include "CompositePricingStrategy.h" void CompositePricingStrategy ::add(PricingStrategy *ps) { pricingStrategies->insert( pricingStrategies->begin(), ps); } ------------------------------------------ ------------------------------------------ // BestForCustomerPricingStrategy.h #ifndef BestForCustomerPricingStrategy_h #define BestForCustomerPricingStrategy_h #include "CompositePricingStrategy.h" class BestForCustomerPricingStrategy : public CompositePricingStrategy { public: virtual Money * getTotal(Reservation *context); }; #endif ------------------------------------------ ------------------------------------------ // BestForCustomerPricingStrategy.cpp #include \ "BestForCustomerPricingStrategy.h" Money * BestForCustomerPricingStrategy ::getTotal(Reservation *context) { vector::iterator i; i = pricingStrategies->begin(); Money *lowest = (*i)->getTotal(context); i++; for (; i != 0; i++) { Money *price = (*i)->getTotal(context); if (*price < *lowest) { lowest = price; } } return lowest; } ------------------------------------------ *** discussion **** inheritance and abstract classes def: an abstract class is a class that is not supposed to be instantiated. It may provide some methods, such as the add method, that are inherited by subclasses, and does provide a convenience. Q: What is the difference between an abstract class and an interface? An abstract class actually has some method implementations. Also not the distinction between the implementation of interfaces and the subclassing links on the DCD (see Fig. 23.15). Q: in the implementation of this last pricing strategy, where does the field (data member) pricingStrategies come from? it's inherited from the superclass Q: How do pricing strategies get added to the composite? through the inherited add method **** passing aggregate objects as parameters Q: Why pass Reservation objects to the pricing strategy, instead of just passing the collection of flights? this increases flexibility, because the Reservation object has more intelligence, and potentially more methods that may be useful in the future, than just the collection of flights. **** creation of multiple strategies how to create all of these strategies? Goal: - evolve into a useful flexible scheme. For example we could start with a SaleCitiesPricingStrategy with no cities in it... Then add new strategies as desired. Q: at what point in making a reservation can we discover new pricing strategies that would apply to the reservation? 1. when the reservation is created (generic) 2. customer based, requires new use case Q: What would a use case for getting the senior citizen discounts pricing strategies created Work through that design (see figures 23.17-18) **** other uses of the composite pattern creating macros of commands, which are just composites of commands **** exercises Q: how would you handle getting 25 percent off the cost of a reservation for taking a business class flight on Tuesday? Q: How would you handle a buy one get one free sale?