strategy-csharp

strategy-csharp - CHAPTER 7 Behavioral Patterns Strategy...

Info iconThis preview shows pages 1–11. Sign up to view the full content.

View Full Document Right Arrow Icon
Background image of page 1

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 2
Background image of page 3

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 4
Background image of page 5

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 6
Background image of page 7

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 8
Background image of page 9

Info iconThis preview has intentionally blurred sections. Sign up to view the full version.

View Full DocumentRight Arrow Icon
Background image of page 10
Background image of page 11
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: CHAPTER 7 Behavioral Patterns: Strategy, State, and Template Method Behavioral patterns are concerned with algorithms and communication between them. The operations that make up a single algorithm might be split up between dif~ ferent classes, making a complex arrangement that is difficult to manage and main~ rain. The behavioral patterns capture ways of expressing the division of operations between classes and optimize how the communication should be handled. In this first chapter on behavioral patterns, we’ll look at three simple but very useful pat- terns: the Strategy, State, and Template Methods. Strategy Pattern Role The Strategy pattern involves removing an algorithm from its host class and putting it in a separate class. There may be different algorithms (strategies) that are applicable for a given problem. If the algorithms are all kept in the host, messy code with lots of con- ditional statements will result. The Strategy pattern enables a client to choose which algorithm to use from a family of algorithms and gives it a simple way to access it. The algorithms can also be expressed independently of the data they are using. Illustration A classic illustration of the Strategy pattern is found in the choice of algorithms for sorting. There are many sorting algorithms, and although some, such as Quicksort, are generally very fast, there are situations when this would be a poor choice and another algorithm, such as Mergesort, would perform better. Even the linear sorts, such as Shellsort, can perform very well under certain conditions. When studying sorting, one learns about the different conditions to consider and how to optimize. the choice of algorithms. This is a strategy that can be captured in the Strategy pattern. 139 Sorting lends itself to animation, as shown in Figure 7—1. The graph plots the index against the value at successive stages in the sort. Thus, initially the box shows a scat~ ter of points. As the algorithm progresses, the points start to converge on the diago— nal, indicating that the values are in the correct positions in the list. The lefthand window shows Mergesort in action, and the righthand window shows Quicksort. @350 at Figure 7—1. Strategy pattern illustration—sorting objects with Mergesort and sorting primitive types with Quicksort In terms of strategy, the animator is set up so that the user indicates the type of items being sorted (at a very rough level in this example). The underlying Strategy pattern then selects an appropriate sort method. In this case, larger values (objects) that have costly compare operations are sent to Mergesort, which uses the lowest number of comparisons of all popular sorts. On the other hand, Quicksort can go very fast with primitive items (Where the comparisons are cheap), so it is preferred for those types of values. The third button is there because of a limitation of Quicksort: without careful programming, it is very slow with reversed data. This button can be used to activate Mergesort. The Strategy pattern makes it easy to add other criteria and sorts to the animator as needed. Design The design of the Strategy pattern is encapsulated in the UML diagram in Figure 7~2. Within a given Context, an appropriate strategy is chosen from an available family of strategies. The algorithm in the strategy is then followed through to a conclusion. 140 I Chapter7: BehavioraIPattems:Strategy,State,andTemplateMethod <<interface>> lStrategy +Algorithm() StrategyA +Algorithm() StrategyB +Algorithm( ) Figure 7—2. Strategy pattern UML diagram The roles for the players in this pattern are as follows: Context A class that maintains contextual information for an IStrategy object’s algo- rithm to work on IStrategy Defines an interface common to all the strategies StrategyA, StrategyB Classes that include algorithms that implement the IStrategy interface QUIZ Match the Strategy Pattern Players with the Sorting Animator Illustration To test whether you understand the Strategy pattern, cover the lefthand column of the table below and see if you can identify its players among the items from the illustrative example (Figure 7—2), as shown in the righthand column. Then check your answers against the lefthand column. Context The GUI, the list generator, and the selection ofthe Strategy Strategy ‘ (lass containing the methods used for a particular sort IStra’cegy Sorting interface (e.g., specifying the list and its item type) Algorithm Mergesort orQuicksort Strategy Pattern I 141 ———————-————i As defined, the Context aggregates an object of the Chosen Strategy type. Generally, it will only have access to the main method that the algorithm requires. If it needs more information from the Strategy, this should be included in the IStrategy inter- face. On the other hand, the Strategy will need to work within the Context and access its state. 1 Implementation The theory code for the Strategy pattern (Example 7~1) does not need any new C# 3.0 features. It relies on aggregation of the IStrategy interface in the Context (line 13). The client calls the Algorithm method on the Context (line 59), and it is routed through to the method of the strategy applicable at the time. In this example, the strategies have Move methods that count up and down. A random number generated in the client determines when to switch from counting up to counting down. The resulting output is shown in line 65. Example 7-1. Strategy pattern theory code 1 using System; 2 3 // Strategy Pattern Judith Bishop Oct 2007 4 // Shows two strategies and a random switch between them 5 6 // The Context 7 class Context { 8 // Context state 9 public const int start = 5; 10 public int Counter = 5; 11 12 // Strategy aggregation 13 IStrategy strategy = new Strategy1(); 14 15 // Algorithm invokes a strategy method 16 public int A1gorithm() { 17 return strategy.Move(this); 18 } 19 20 // Changing strategies 21 public void SwitchStrategy() { 22 if (strategy is Strategyl) 23 strategy = new Strategy2(); 24 else 25 strategy = new Strategy1(); 26 } 27 } 28 29 // Strategy interface 30 interface IStrategy { 31 int Move (Context c); 32 } 33 142 I Chapter7: Behavioral Patterns:Strategy,State,andTempIateMethod Example 7—1. Strategy pattern. theory code (continued) 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 Some key points about the implementation of the Strategy pattern are: 1 ' The Context will often contain a switch statement or a cascading if statement, where information is processed to reach a decision on which Strategy to adopt. ° If the strategies are simple methods, they can be implemented Without enclosing I classes, and the delegate mechanism can be used to hook the chosen Strategy 3 into the Context at runtime. i l ' Extension methods can be used to define new strategies independently of the original classes that they support. ‘ } /* 4 */ // Strategy 1 class Strategyl : IStrategy { public int Move (Context c) { return ++c.Counter; } // Strategy 2- class Strategyz : IStrategy { public int Move (Context c) { return —-c.CounteI ; } } // Client static class Program { static void Main () { Context context = new Context(); i context.SwitchStIategy()3 r Random r = new Random(37); for (int i=Context.start; i<=Context.start+15; i++) { if (I.Next(3) == 2) { I Console.write("]| "); g context.SwitchStrategy(); ’ } Console.Write(context.Algorithm() +" ")3 t } , . Console.WriteLine(); } } Output Il567||6|I78910||9876|I7H65 ‘ Strategy Pattern I 143 Example: Sorting Animator The program that produces the animations in Figure 7—1 is shown in Example 7—2. Consider first the Context (lines 61—86). ButtonClick is activated from the GUI and, based on the button clicked, will decide on a strategy to follow. In other words, it will select one of the available strategy classes and instantiate it. After generating data from the class at line 15 (not shown in full here), it activates the GUI window and starts the sort. We don’t show the full sorting algorithms here, only the interaction with the Context (see lines 96—112 for Mergesort). Input is the list that is being sorted, and the algorithms contain strategic calls to update the user interface through the UpdateUI event. Example 7-2. Strategy pattern example code—Sorting Animator 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Windows.Forms; 5 using System.Drawing; 6 using System.Threading; 7 8 namespace Strategy { 9 10 // Strategy Pattern Judith Bishop and 0—] Miller Sept 2007 11 // Gives a choice of sort routines to display 12 // Algorithms and GUI adapted from a Java system at 13 // http://www.geocities.com/SiliconValley/Network/1854/Sort1.html 14 15 static class StartSetGenerator { 16 private static List<int> myList; 17 18 public static IEnumerab1e<int> GetStaItSet() { 19 // omitted 20 } 21 22 class StrategyView<T> : Form 23 where T : IComparable<T> { 24 PictureBox pb; 25 Func<IEnumerable<T>> Generator; 26 27 // Constructor to set up the GUI 28 public StrategyView(Func<IEnumerable<T>> generator) { 29 // omitted 30 31 public void DrawGraph(IEnumerable<T> list) { 32 it (pb.Image == null) 33 pb.Image = new Bitmap(pb.width, pb.Height); 34 Graphics g = Graphics.FromImage(pb.Image); 35 g.Clear(ColoI.White); 36 g.DIawRectang1e(Pens.Blue, 19, 19, 202, 202); 37 g.Dispose(); 38 Bitmap b = pb.Image as Bitmap; 39 144 l Chapter7: Behavioral Patterns: Strategy, State, andTempIate Method Example 7—2. Strategy pattern example code—Sorting Animator (continued) 1 40 // Plots the index x against the value val of all elements in the list 41 // IEnumerable<T>.Count is an extension ; 42 int listSize = list.Count(); | 43 int x = 0; ; 44 foreach (T item in list) { I 45 // val must be a nullable integer. The as operator will return null E 46 // if it cannot convert the item to int l 47 int? val = item as int?; ; 48 if (Ival.HasValue) 49 val A 0; I 50 // Drawing methods do not handle nullable types 1 51 b.5etPixel(x + 20, 20 + 200 — ((int)va1), Color.Black); 1 52 x++; I 53 } g 54 ; 55 this.Refresh(); 56 Thread.Sleep(100); ; 57 Application.DoEvents(); 58 } ’ 59 60 // The Context 61 void ButtonClick(object sender, EventArgs e) { 62 Button control = sender as Button; 63 SortStrategy<T> strategy = null; 64 65 switch (control.Name) { 66 case "LargeItems": 67 strategy = new MergeSorter<T>(); 68 break; 69 case "SmallItems": 70 strategy = new QuickSorter<T>(); 71 break; 72 case “ReversedList”: 73 strategy = new MergeSorter<T>(); 74 break; f 75 } 76 77 IEnumerable<T> newlist = Generator(); f 78 DrawGraph(newlist); l 79 if (strategy == null) f 80 return; ? 81 82 // DrawGraph will be invoked during sorting when I 83 // the UpdateUI event is triggered 84 strategy.UpdateUI += new Action<IEnumerable<T>>(DrawGraph); 85 strategy.50rt(newlist); 86 } 87 } 88 ‘- 3 89 // Strategy interface I 90 interface SortStrategy<T> where T : IComparable<T> { 91 event Action<IEnumerable<T>> UpdateUI; é Strategy Pattern I 145 Example 7—2. Strategy pattern example code—Sorting Animator (continued) 92 void Sort(IEnumerable<T> input); 93 } 94 95 // Strategy 1 96 class MergeSorter<T> : SortStrategy<T> 97 where T : IComparable<T> { 98 99 public event Action<IEnumerable<T>> UpdateUI; 100 101 List<T> aux; 102 int opCount = 0; 103 public void Sort(IEnumerable<T> input) { 104 UpdateUI(input); 105 opCount++; 106 List<T> sorteditems = new List<T>(input); 107 aux = new List<T>(sorteditems.Count); 108 for (int i = 0; i < sorteditems.Count; i++) 109 aux.Add(detault(T)); 110 MergeSort(ref sorteditems, 0, sorteditems.Count — 1); 111 UpdateUI(sorteditems); 112 } 113 114 private void Merge(ref List<T> a, int 1, int m, int r) { 115 // omitted 116 117 private void MergeSort(ref List<T> a, int 1, int r) { 118 // omitted 119 } 120 121 // Strategy 2 122 class QuickSorter<T> : SortStrategy<T> 123 where T : IComparable<T> { 124 125 public event Action<IEnumerab1e<T>> UpdateUI; 126 127 int opCount = 0; 128 public void Sort(IEnumerable<T> input) { 129 UpdateUI(input); 130 opCount++; 131 List<T> sorteditems = new List<T>(input); 132 133 QuickSort(ref sorteditems, 0, sorteditems.Count — 1); 134 UpdateUI(sorteditems); 135 } 136 137 private int Partition(ref List<T> a, int 1, int r) { 138 // omitted 139 140 private void QuickSort(ref List<T> a, int 1, int r) { 141 // omitted 142 } 143 144 static class Program { 146 Chapter 7: Behavioral Patterns: Strategy, State, and Template Method Example 7—2. Strategy pattern example code—Sorting Animator (continued) 145 146 147 148 149 150 151 static void Main() { Application. EnableVisualStyles( )3 Application . SetCompatibleTextRenderingDefault(false); Application. Run(new StrategyView<int> (StaItSetGenerator. GetStaItSet) ); } . } } UpdateUI is an event that is set in line 84 (in the Context) to refer to DrawGIaph. This is a more transparent way of the Strategy getting back to the animator than having it call DrawGIaph directly. Notice that DrawGraph (lines 31—58) has an interesting loop that uses a new feature in C# 2.0: nullable types. C# Feature—Nullable Types Nullable types add to primitive types and structs the ability to include an “undefined value.” In keeping with objects, the value is called null, and it can be assigned and checked for. In programs, all primitive types are assigned default values on instantiation. Therefore, the ability to assign null to numeric and Boolean types is particularly useful when deal~ ing with databases and other data types containing elements that may not be assigned a value. For example, a Boolean field in a database can store the values true or false, or it may be undefined. In C#, a nullable type is declared with the addition of a question mark (e.g., int? x). An extra property~—HasValue—can then be used to check whether a value is non-null. To convert back to a non~nullable type, use the as operator. as will return null if it can- not convert the value. For example, int? val = DateTime.Now as int? ; cf. C# Language Specification Version 3.0, September 2007, Section 4.1.10 Consider the loop in question. The items in the list are of type T, and it is possible that they might not have values. The cast to int on line 47 will therefore be trapped unless null is included as a possibility for val. In the next line, we can convert any possible nulls to zeros. Then, on line 51, we see that we have to convert the int? type to int so that it can be used in arithmetic: 44 45 46 47 48 49 50 51 52 53 toreach (T item in list) { // val must be an integer. The as conversion needs it // also to be a non—nullable, which is checked by the 7 int? val = item as int?; if (lval.HasValue) val = 0; // Drawing methods do not handle nullable types b.5etPixel(x + 20, 20 + 200 ~ ((int)val), Color.Black); x++; Strategy Pattern I 147 Use There are many examples where a different algorithm can be passed to an active method or class. Dialog boxes, for example, can have different validating strategies depending on the kind of data required, whereas graph—drawing programs can accept algorithms fdr drawing pie charts, histograms, or bar Charts. The C# 3.0 LINQ sup- port libraries (for database queries) use this kind of separation between data and algorithm extensively. ; Use the Strategy pattern when - Many related classes differ only in their behavior. - There are differentalgorithms for a given purpose, and the selection criteria can be codified. ' The algorithm uses data to which the client should not have access. Exercises 1. One of the criteria for choosing a sorting algorithm is Whether the data is ini- tially presorted, reverse-sorted, or in random order. Add to the Generator class in the Sorting Animator so that different arrangements of data in the list can be cre- ated. Then, add some more buttons to make the user’s description of the prob— lem at least two—dimensional (i.e., size of elements and arrangement of data). Change the strategy selection accordingly. 2. Add to the animator a linear sort like Shellsort, and define its criteria so that it can also be selected when appropriate. (Hint: Shellsort is good enough for short lists.) 3. In the proxy-protected version of MySpaceBook (Chapter 2), the registration pro- cess does not check whether the input is valid. Decide on more rich input (such as email addresses and requirements for passwords), and implement the input of each field using the Strategy pattern. State Pattern Role The next pattern in this group, the State pattern, can be seen as a dynamic version of the Strategy pattern. When the state inside an object Changes, it can change its behavior by switching to a set of different operations. This is achieved by an object variable changing its subclass, within a hierarchy. 148 I Chapter7: Behavioral Patterns: Strategy, State, and Template Method Use the Power of C# 3.0 to Solve Real-World Problems O’REILLY® fudz’t/o Bis/90p ...
View Full Document

Page1 / 11

strategy-csharp - CHAPTER 7 Behavioral Patterns Strategy...

This preview shows document pages 1 - 11. Sign up to view the full document.

View Full Document Right Arrow Icon
Ask a homework question - tutors are online