150 likes | 157 Views
This presentation discusses the implementation and applicability of the Template Method and Strategy patterns. It covers the intent, participants, and consequences of using these patterns.
E N D
GoF Template Method (pp. 325-330)GoF Strategy (pp. 315-323)PH Single User Protection (pp. 34-40) Presentation by Julie Betlach 6/08/2009
GoF Template Method (pp. 325-330) Template Method Pattern - Intent / Applicability • Intent • Define the skeleton of an algorithm, deferring some steps to subclasses. • Template Method lets subclasses redefine certain steps of an algorithm, without changing the algorithm’s structure. • Applicability – Use Template Method Pattern… • To implement the invariant part of an algorithm, and leave it up to subclasses to implement the part that can vary. • When common code in subclasses should be factored and localized in a common base class to avoid code duplication. • To control extensions to subclasses. (Hook operations)
GoF Template Method (pp. 325-330) Template Method Pattern - Participants • AbstractClass • Defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm. • Implements a template method defining the skeleton of an algorithm. It calls primitive operations as well as other operations in the AbstractClass (or other classes). • ConcreteClass • Implements primitive operations to carry out subclass-specific steps of the algorithm. Hollywood Principle – “Don’t call us, we’ll call you.” => Parent class calls operations of subclass. Note: Some concrete AbstractClass methods can also be defined.
GoF Template Method (pp. 325-330) Template Method Pattern - Participants void Application::OpenDocument (const char* name) { if (!CanOpenDocument(name)) { return; } Document* doc = DoCreateDocument(); if (doc) { _docs->AddDocument(doc); AboutToOpenDocument(doc); doc->Open(); doc->DoRead(); } } Template Method PrimitiveOperation Concrete AbstractClass Operation Basic Algorithm is the same for all documents.
GoF Template Method (pp. 325-330) Template Method Pattern - Implementation Template Method – Don’t want this to be overridden, so make it nonvirtual member function. void Application::OpenDocument (const char* name) { if (!CanOpenDocument(name)) { return; } Document* doc = DoCreateDocument(); if (doc) { _docs->AddDocument(doc); AboutToOpenDocument(doc); doc->Open(); doc->DoRead(); } } Primitive Operations that must be overridden (make these pure virtual in abstract class). Concrete AbstractClass Operation Primitive Operation that has a default behavior in abstract class = Hook operation. Naming Convention suggestion is confusing. Are DoCreateDocument and DoRead from the example called Template Methods? I think book should have said that MacApp framework prefixes primitive operation names with “Do”.
GoF Template Method (pp. 325-330) Related Patterns • Factory Methods – Are often called by template methods. Example: Factory Method DoCreateDocument is called by Template Method OpenDocument. • Strategy – Template Methods use inheritance to vary part of an algorithm. Strategies use delegation to vary the entire algorithm.
GoF Strategy (pp. 315-323) Strategy Pattern - Intent / Applicability • Intent • Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. • Applicability – Use Strategy Pattern when… • Many related classes differ only in their behavior. • You need different variants of an algorithm. For example, defining different algorithms based on space-time tradeoffs. • An algorithm uses data that a client shouldn’t know about. • A class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead, move related conditional branches into their own Strategy class.
GoF Strategy (pp. 315-323) Strategy Pattern - Participants • Strategy • Declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy. • ConcreteStrategy • Implements the algorithm using the Strategy interface. • Context • Is configured with a ConcreteStrategy object • Maintains a reference to a Strategy object • May define an interface that lets Strategy access its data. Picture & Example from: http://www.dofactory.com/Patterns/PatternStrategy.aspx
GoF Strategy (pp. 315-323) Strategy Pattern - Participants http://www.dofactory.com/Patterns/PatternStrategy.aspx Show code in RealWorld Example • Strategy • SortStrategy • ConcreteStrategy • QuickSort • ShellSort • MergeSort • Context • SortedList Picture & Example from: http://www.dofactory.com/Patterns/PatternStrategy.aspx
GoF Strategy (pp. 315-323) Strategy Pattern – Consequences • Good Consequences • Good for families of related algorithms. Inheritance can help factor out common functionality of algorithms. • Alternative to subclassing which allows the developer to vary the algorithm independent of its context. • Strategies eliminate conditional statements. • Provide different implementations of the same behavior. Example: Sorting is goal, but many ways to sort. • Drawbacks • Clients must be aware of different strategies. • Communication overhead between Strategy and Context – some concrete strategies may not need all the parameters passed into them. • Increased number of objects. See Flyweight pattern for an approach to solve this.
GoF Strategy (pp. 315-323) Related Patterns • Flyweight – Strategy objects often make good flyweights.
PH Single User Protection (pp. 34-40) Single User Protection • Read Protection (do not reveal contents) • Disallow streamOut • Disallow getChild (makes sense if you consider example of hiding the family tree information of a person, where getChild returns the name of the person’s descendents.) • Write Protection (protect both attributes and structure) • Disallow streamIn, setName, adopt, orphan • Treat setProtection carefully (explained in multi-user section)
PH Single User Protection (pp. 34-40) Single User Protection • Write Protection (continued) • Prevent deletion • Can’t declare a node as a const in order to get compiler to check this for us, because a node’s protection may change at runtime. • Instead, we can Protect the Destructor by putting it in the Protected section. • Don’t want to make it private because that wouldn’t let subclasses extend the destructor to delete their children or any other objects that they aggregate. • We want a static member function (makes syntax nicer) and we want the subclasses to be able to extend the definition.
PH Single User Protection (pp. 34-40) Single User Protection • Solution = Destroy() will be a Template Method! class Node { public: static void destroy (Node*); // template method protected: virtual ~Node(); virtual bool isWriteable() = 0; // primitive operation virtual void doWarning() = 0; // primitive operation }; void Node::destroy (Node* node) { if (node->isWriteable()) { delete node; } else { node->doWarning(undeletableWarning); } } Because destroy is static, it can’t call Node operations directly. But it doesn’t need to because it calls primitive operations in the subclasses. Technically, isWriteable should start with “do” to be clear it is a primitive operation.
PH Single User Protection (pp. 34-40) Single User Protection class Node { public: static void destroy (Node*); // static template method void streamOut (ostream& out); // non-static template method (also not virtual) protected: virtual ~Node(); virtual bool isWriteable() = 0; // primitive operation virtual bool isReadable() = 0; // primitive operation virtual void doWarning() = 0; // primitive operation virtual void doStreamOut() = 0; // primitive operation }; void Node::streamOut (ostream& out) { if (isReadable()) { doStreamOut(); } else { doWarning(unreadableWarning); } } However, if we define another template method which is not static, it is allowed to call Node functions, so it doesn’t need the node passed in.