Go4 Template Method, Strategy, State Patterns Presented By: Matt Wilson
Introduction 2 This presentation originated out of casual talk between former WMS “C++ Book Club” (defunct program) developers who wanted to continue to get together on occasion to discuss technical topics. It’s expected that all Senior Software Engineers understand the G04 Design Patterns well, and thus their occasional review is useful.
Introduction 3 This Presentation Series was created to not only teach what the patterns are, but explain best-practices of when and why you would want to use them Sources used here included the Gang of 4 Design Patterns Book, Head First Design Patterns book, and many online articles and discussion boards on the topic.
Template Method 4
What-is/Why-use Template Method? 5 Good news: Template Method is an Easy/Simple effective G04 pattern to learn. Very commonly used Design Pattern. Template Method is a Non-Virtual class’ Method that calls one or more other of the class’ methods that are Virtual. Subclasses override the Class with the Template Method, and implement their own behavior for the Virtual methods. A Herb Sutter Guideline for good OO design: Prefer to make interfaces nonvirtual, using Template Method. Gives benefits with little to no downside.
What-is/Why-use Template Method? 6 Formal definition: Template Method: “Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. ” Like other G04 Pattern descriptions, it’s very technical/complicated sounding, but it actually very straightforward.
Template Method – UML 7
Template Method Benefits 8 A single class owns the Algorithm. SubClasses don’t need to know about it anymore. Eliminates duplicate code across SubClasses, maximizing reuse. Provides a Framework for SubClass extension. Use Template Method whenever you want to create a method for SubClasses to implement.
Template Method Example (C#) 9 abstract class DataAccessObject { protected string connectionString; protected DataSet dataSet; public virtual void Connect() { // Make sure mdb is available to app connectionString = "provider=Microsoft.JET.OLEDB.4.0; " + "data source=..\\..\\..\\db1.mdb"; } public abstract void Select(); public abstract void Process(); public virtual void Disconnect() { connectionString = ""; } // The 'Template Method' public void Run() { Connect(); Select(); Process(); Disconnect(); }
Template Method Example (C#) 10 class Categories : DataAccessObject { public override void Select() { string sql = "select CategoryName from Categories"; OleDbDataAdapter dataAdapter = new OleDbDataAdapter( sql, connectionString); dataSet = new DataSet(); dataAdapter.Fill(dataSet, "Categories"); } public override void Process() { Console.WriteLine("Categories ---- "); DataTable dataTable = dataSet.Tables["Categories"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["CategoryName"]); } Console.WriteLine(); }
Template Method Example (C#) 11 class Products : DataAccessObject { public override void Select() { string sql = "select ProductName from Products"; OleDbDataAdapter dataAdapter = new OleDbDataAdapter( sql, connectionString); dataSet = new DataSet(); dataAdapter.Fill(dataSet, "Products"); } public override void Process() { Console.WriteLine("Products ---- "); DataTable dataTable = dataSet.Tables["Products"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["ProductName"]); } Console.WriteLine(); }
Template Method Example (C#) 12 class MainApp { /// /// Entry point into console application. /// static void Main() { DataAccessObject daoCategories = new Categories(); daoCategories.Run(); DataAccessObject daoProducts = new Products(); daoProducts.Run(); // Wait for user Console.ReadKey(); }
Template Method Example (C#) - OUTPUT 13 Categories ---- Beverages Condiments Confections Dairy Products Grains/Cereals Meat/Poultry Produce Seafood Products ---- Chai Chang Aniseed Syrup Chef Anton's Cajun Seasoning Chef Anton's Gumbo Mix Grandma's Boysenberry Spread Uncle Bob's Organic Dried Pears Northwoods Cranberry Sauce Mishi Kobe Niku
Template Method Herb Sutter Tips - Virtuality 14 As referenced earlier, Herb Sutter is an advocate of Template Method. See the link for details. In summary, his Guidelines for C++ development regarding this pattern are the following: #1: Prefer to make interfaces nonvirtual, using Template Method. #2: Prefer to make virtual functions private. #3: Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected. #4: A base class destructor should be either public and virtual (common), or protected and nonvirtual (rare).
Template Method Questions ? 15
Strategy Pattern 16
What-is/Why-use Strategy Pattern? 17 When C++ Guru’s (Sutter, Myers, etc.) tell us: “Prefer Composition over Inheritance”, it’s a mistake to simply believe that they mean ”Inheritance is bad” and discourage its use in your designs. That is not what they mean. What they are actually telling us, is to implement the Strategy Pattern! Why are they telling us to use it? Because Strategy Pattern is a more flexible, Composition alternative to Inheritance.
What-is/Why-use Strategy Pattern? 18 Formal definition: “The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.” In other words: The Strategy Pattern allows you to dynamically change the code Methods execute during run time.
What-is/Why-use Strategy Pattern? 19 Instead of utilizing Inheritance to encapsulate different behaviors inside different SubTypes, it uses Composition to encapsulate different behaviors inside member variables. Strategy Pattern is useful for eliminating fragile if-else/switch code. Note: Strategy Pattern is very similar to State Pattern (more on this later)
Strategy Pattern - UML 20 Strategy Pattern uses Inheritance to enable Composition:
Strategy Pattern – SOLID Design Principles 21 Strategy Pattern is in harmony with SOLID Design Principles for good OO DesignSOLID Open Closed Principle Open for extension, but closed for modification Or as I like to put it: Writing new code shouldn’t require a change to existing code As new behaviors are needed, new Strategies can be created without effecting any existing code. Dependency Inversion Principle: Classes shouldn’t have references to Concrete Classes Violation creates dependency problems, longer compile times, and prohibits Unit Testing/dependency injection.
Strategy Pattern – SOLID Design Principles 22 Strategy Pattern also helps keep the interface of SuperClasses clean and uncluttered from needing to have methods that don’t belong on some SubClasses. Example: Should fly() be a method on a CBirdClass? Some bird Subclasses can’t fly! Instead, use Strategy Pattern to define a flyBehavior() interface.
Strategy Pattern – Example (Java) 23 /// /// The 'Strategy' abstract class /// abstract class SortStrategy { public abstract void Sort(List list); }
Strategy Pattern – Example (Java) 24 class QuickSort : SortStrategy { public override void Sort(List list) { list.Sort(); // Default is Quicksort Console.WriteLine("QuickSorted list "); } class ShellSort : SortStrategy { public override void Sort(List list) { ShellSort(list); Console.WriteLine("ShellSorted list "); } class MergeSort : SortStrategy { public override void Sort(List list) { MergeSort(list); Console.WriteLine("MergeSorted list "); }
Strategy Pattern – Example (Java) 25 class SortedList { // NOTE: INSTEAD OF HAVING MULTIPLE SUBCLASSES OF SortedList, // you only have one that contains a dynamic strategy/behavior. private List _list = new List (); private SortStrategy _sortstrategy; public void SetSortStrategy(SortStrategy sortstrategy) { this._sortstrategy = sortstrategy; } public void Add(string name) { _list.Add(name); } public void Sort() { _sortstrategy.Sort(_list); // Iterate over list and display results foreach (string name in _list) { Console.WriteLine(" " + name); } Console.WriteLine(); }
Strategy Pattern – Example (Java) 26 class MainApp { /// /// Entry point into console application. /// static void Main() { // Two contexts following different strategies SortedList studentRecords = new SortedList(); studentRecords.Add("Samual"); studentRecords.Add("Jimmy"); studentRecords.Add("Sandra"); studentRecords.Add("Vivek"); studentRecords.Add("Anna"); studentRecords.SetSortStrategy(new QuickSort()); studentRecords.Sort(); studentRecords.SetSortStrategy(new ShellSort()); studentRecords.Sort(); studentRecords.SetSortStrategy(new MergeSort()); studentRecords.Sort(); // Wait for user Console.ReadKey(); }
Strategy Pattern vs. Template Method 27 Strategy Pattern & Template Method have some things in common. Both patterns provide clients a way to execute different behavior, based on using different Types that encapsulate different behavior. However, Temple Method enables this through Inheritance, while Strategy enables it though Composition. Template Method provides a concrete method that “owns” the algorithm, whereas in Strategy pattern, there is no “owner” of an algorithm. You may or may not prefer an “owner” depending upon the context of your specific needs. Strategy is more in line with SOLID dependency inversion principles, and is more flexible, however using Template Method may give you simpler designs which is also important. Basic rule of thumb: Use Template Method whenever you are creating Virtual Methods. Use Strategy Pattern whenever you want to change class behavior at runtime, without the use of Inheritance.
Strategy Pattern Questions ? 28
State Pattern 29
What-is/Why-use State Pattern? 30 The Go4 State Pattern is an OO way to create a State Machine in software. Definition of State Machine: “A state machine, is a model used to design both computer programs and sequential logic circuits. It can be in one of a finite number of states. The machine is in only one state at a time; the state it is in at any given time is called the current state. It can change from one state to another when initiated by a triggering event or condition; this is called a transition. A state machine is defined by a list of its states, and the triggering condition for each transition.”computer programssequential logic states
State Machine Model Example: 31
What-is/Why-use State Pattern? 32 Why implement a State Machine? State machines are incredibly useful for modeling and implementing complex processes. It enables your program/state-machine to change its behavior during runtime, such that different code executes in Methods based on the current State of the machine. State Pattern is useful for eliminating fragile if-else/switch code.
What-is/Why-use State Pattern? 33 Without a State Machine: CYourClass::DoSomething() { if (x) then dox(); else if (y) then do(y)… etc. } With a State Machine CYourClass::DoSomething() { state->doit(): } // CLEAN extensible OO - good SOLID Principles:
What-is/Why-use State Pattern? 34 Does this Pattern sound Familiar? “Enables your program to change its behavior during runtime” “Pattern is useful for eliminating fragile if-else/switch code.” ? Well let’s look at the UML? Does this look familiar?
State Pattern - UML 35
State Pattern UML 36 Compare to Strategy Pattern UML
State Pattern vs. Strategy Pattern 37 The State Pattern has the same UML Structure as the Strategy Pattern. So is it the same Pattern? Practically yes, but Technically no. A “State” and a “Strategy” can be looked at as the same thing, a class owned via composition, that encapsulates different behaviors. When WMS had OO Training, the teacher said these two patterns “can be looked at as the same thing”, and that is true in regards to their Structure. However the difference is in implementation details. The State Pattern “is-a” or “type-of” Strategy Pattern, but State Pattern adds State Machine logic to drive the setting of the current States/Strategies. The main difference: In Strategy Pattern, the composited Strategies/States are changed at runtime typically by the client who wants control over what Strategy/State they want to use. In State Pattern, the composited States/Strategies are not changed by the client, but by the rules of the State Machine enforced in code.
Simple State Pattern Example (C#) 38 using System; class MainApp { static void Main() { // Setup context in a state Context c = new Context(new ConcreteStateA()); // Issue requests, which toggles state c.Request(); // Wait for user Console.Read(); }
Simple State Pattern Example (C#) 39 // "State" abstract class State { public abstract void Handle(Context context); } // "ConcreteStateA" class ConcreteStateA : State { public override void Handle(Context context) { context.State = new ConcreteStateB(); } // "ConcreteStateB" class ConcreteStateB : State { public override void Handle(Context context) { context.State = new ConcreteStateA(); }
Simple State Pattern Example (C#) 40 // "Context" class Context { private State state; // THIS IS THE Composited State/Strategy // Constructor public Context(State state) { this.State = state; } // Property public State State { get{ return state; } set { state = value; Console.WriteLine("State: " + state.GetType().Name); } public void Request() { state.Handle(this); } }
Simple State Pattern Example (C#) 41 Output: State: ConcreteStateA State: ConcreteStateB State: ConcreteStateA State: ConcreteStateB State: ConcreteStateA
State Pattern 42 Most of the time to create a State pattern, you will begin by creating a State UML diagram for your States and their Transitions, then implement the rules in code. Many tools exist that generate code from State Diagrams.
State Pattern Questions ? 43