introduction to design patterns - .net, java, and mobile ... · introduction to design patterns ......

31
Copyright © Intertech, Inc 2014 Rev: 2 1-1 Chapter 1 Introduction to Design Patterns Objectives: Understand the nature of software design patterns. Survey the classic “Gang of Four” design patterns. Distinguish between structural, creational and behavioral patterns. Review some core UML notation. Study your first pattern, the "Strategy" behavioral pattern. Clarify the nature of this course and the associated lab work.

Upload: lamkien

Post on 26-May-2018

214 views

Category:

Documents


0 download

TRANSCRIPT

Copyright © Intertech, Inc 2014 Rev: 2 1-1

Chapter 1

Introduction to Design Patterns

Objectives:

Understand the nature of software design patterns.

Survey the classic “Gang of Four” design patterns.

Distinguish between structural, creational and behavioral patterns.

Review some core UML notation.

Study your first pattern, the "Strategy" behavioral pattern.

Clarify the nature of this course and the associated lab work.

Introduction to Design Patterns

1-2 Copyright © Intertech, Inc 2014 Rev: 2

Chapter Overview

Design patterns provide a formal, predictable way to solve common programming

problems. In this initial chapter, you will come to understand the overall nature of

patterns and survey the classic “Gang of Four” patterns upon which this course is

based.

This chapter will also provide a quick and painless review of the key features of the

Unified Modeling Language (UML), which is the lingua franca of pattern notation.

Next, you will examine the Strategy behavioral pattern, as seen through the eyes of C#,

VB.NET and Java.

After this point you will come to understand the nature of the remaining class material

and the related lab work.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-3

Understanding the Nature of Design Patterns

• Software professionals can become very ‘religious’ regarding the topic of design patterns…

• Hardcore “patterns people” may think a software application is complete junk unless the code base has X number of patterns baked within.

• Newcomers often think the entire topic is something mysterious or intrinsically difficult, and therefore avoided all together.

• In reality, neither extreme is correct. As with most things in life, a middle-of-the-road approach is typically best.

• Use patterns when they are truly useful, don’t use them simply because you can (or feel you should).

• Small in-house apps, prototypes, or simple utility programs may become more complex than necessary if the code base becomes chock full of patterns.

• Larger scale applications (on the other hand) can benefit greatly from various patterns, in that the code base is ‘ready for the long haul’.

• To be sure, a well placed pattern can yield a flexible, easily maintainable and extensible system.

• However, what exactly is a software design pattern?

• Simply put, design patterns are nothing more than a recognized, formal way to solve common coding difficulties.

• As you have certainly seen in your career, most software applications tend to grapple with the same basic problems.

• Simplify complex object creation, cleanly add new functionality to an existing code base, separate GUI from functionality, etc.

• Rather than creating ad-hoc solutions for such problems, the chances are quite good that a design pattern already exists to solve your dilemma.

Introduction to Design Patterns

1-4 Copyright © Intertech, Inc 2014 Rev: 2

• Using design patterns, developers can view their code base as a set of software agents which work together to solve problems.

• Design patterns help us think of our software applications using higher level abstractions.

• Rather than *only* thinking about common programming constructs (data types, classes, interfaces, switch statements, for-loops, etc), we can learn to recognize and incorporate useful patterns.

• For example, the Decorator pattern provides a solution to the problem of adding new functionality to non-extendable classes.

• The Façade pattern provides a way to expose a complex sub-system using a much more manageable front end.

• While a given pattern will ultimately make use of common programming constructs (data types, classes, interfaces, switch statements, for-loops, etc) when implemented, patterns themselves help paint a ‘bigger picture’.

• The nice thing about design patterns is that they are typically agnostic in nature.

• Most patterns are not tied to a specific language, particular programming construct or particular platform API.

• Most patterns can be implemented in various frameworks (COM, .NET, Java 2) and languages (Java, C#, VB, Delphi, C++, etc.).

• Once the overall nature of the pattern is understood, developers add meat to the bones using their language (and platform) of choice.

• Numerous design patterns exist in the software world today, and ultimately nothing is preventing you from creating your own (if people buy into it or not is another question).

• Furthermore, there is no ‘master list’ of patterns that all developers agree upon.

• If you were to ask 10 developers to list the ‘top five patterns’, you’ll most likely get 10 unique responses.

• While this is true, if you pick up any book on the subject, you will find a set of common patterns most programmers agree are very useful.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-5

• Many of the ‘agreed upon’ patterns were first formalized in the seminal book on the subject, Design Patterns: Elements of Reusable Object-Oriented Software (aka, the Gang of Four [GOF] book).

• ‘Gang of Four’ refers to book’s four authors- Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.

• Their book examines 23 software design patterns, which are nowadays understood as the ‘classic patterns’.

• The GOF book illustrated these patterns via UML diagrams, C++ code and examples from Smalltalk.

• Numerous additional books have been written that implement these patterns in additional languages (C#, Java, VB, et. al.).

• Beyond the classic GOF patterns, be aware that a great number of additional patterns exist, which come from a variety of sources.

• Some of these design patterns focus on a specific problem domain, such as building multithreaded applications / parallel processing.

• Other design patterns focus on building secure systems or other higher level architectural issues.

• As well, some patterns focus on building a particular type of software application (video games, web blogs, interactive kiosks, database interactivity, etc).

• Regardless of the ‘flavor’ of a design pattern, a given pattern is typically documented as so:

• First, every pattern is given name (e.g., the Iterator pattern, the Observer pattern, the Strategy pattern, etc).

• Second, because design patterns are agnostic in nature, patterns are presented using UML diagrams (more on UML later in this chapter).

• Next, a given pattern explains the ‘roles’ each aspect of the pattern plays (who is the caller? How are related classes packaged together, etc.)

• Optionally, the pattern is illustrated in code using a concise example in a particular programming language.

Introduction to Design Patterns

1-6 Copyright © Intertech, Inc 2014 Rev: 2

• Remember, the exact programming language used is not important as far as a pattern is concerned.

• The ‘classic’ GOF patterns could just have easily been exampled in C#, Java, VB or Ruby (rather than C++ and Smalltalk).

• Many patterns can even be applied in non-object oriented languages such as C.

• However, other design patterns demand that the implementation language support OOP concepts, such as classical inheritance.

• It is also important to understand that a given programming language / platform may provide ‘shortcuts’ which help you implement a given pattern more easily.

• For example, .NET developers can quickly incorporate the Decorator pattern using .NET 3.5 "extension methods".

• Java (and .NET) programmers have helper classes and interfaces which allow them to quickly incorporate the Iterator pattern.

• To this end, a given pattern could be implemented in your code base using the classic ‘longhand’ approach or via language-specific shortcuts.

• The trade off will typically revolve around full control over the pattern’s operation verses ease of implementation.

• If you roll your own ‘longhand’ pattern implementation, you can easily incorporate custom error handling, logging services, and so on.

• Using language-specific shortcuts on the other hand, may encapsulate a number of details you cannot easily change.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-7

• Also be aware that most patterns can actually be implemented in a variety of ways.

• For example, a given pattern could be implemented using interfaces or using abstract base classes (or a combination of both).

• Some patterns could be implemented using the “Is-A” or “Has-A” relationship (or a mixture of both).

• Given this, be aware that you might see the same pattern implemented in slightly different ways based on your source.

• It is not at all uncommon to find different books / websites describing the same exact pattern using different techniques.

• This is *not* to say one approach is ‘better’ or ‘worse’. Typically it just boils down to personal programming preferences of the individual.

• Remember, implementation differences are less important than understanding the problem the pattern is attempting to solve.

Introduction to Design Patterns

1-8 Copyright © Intertech, Inc 2014 Rev: 2

Categorizing the Classical GOF Design Patterns

• The GOF book defines 23 classic patterns, which can be grouped into three broad categories.

• The following table documents each category, and the patterns which fall under a given category.

• Additional details of many of these patterns will be given over the remainder of this course, so for the time being, just absorb the big picture.

Pattern Category

Meaning in Life Classic Patterns of this Category

Structural These patterns are concerned with how classes and objects can be composed to obtain new functionality.

Adapter, Bridge, Composite, Decorator, Façade, Flyweight, Proxy

Creational These patterns have to do with how objects are instantiated into memory, typically in an attempt to simplify their creation.

Abstract Factory, Builder, Factory Method, Prototype, Singleton

Behavioral These patterns are concerned with communication between objects.

Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor

• Design patterns can be further categorized into “class-creation” patterns and “object-creational” patterns.

• Class-creation patterns use inheritance (“Is-A”) in the pattern implementation.

• Object-creation patterns use containment/delegation (“Has-A”) in the pattern implementation.

• As you might guess, class creation patterns are only useful if you are able to subclass an existing type.

• If this is not possible, the object creation pattern can typically be used to yield the same end result.

• Furthermore, in some cases, you could make use of either approach with the same end result.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-9

The Structural Design Patterns

• Structural design patterns are used to describe how objects and classes can be combined to build new, larger (not to mention useful) programming entities.

• As you will see, many patterns in this category favor composition (Has-A) over classical inheritance (Is-A) to achieve the desired result.

• The GOF book identifies seven common structural patterns, briefly detailed here:

• Adapter Pattern: Used to make one class conform to the structure of another class, in order to simplify programming.

• Bridge Pattern: Used to separate interface from implementation.

• Composite Pattern: Allows you to build new objects via composition of existing objects.

• Decorator Pattern: Used to extend the functionality of an object dynamically.

• Façade Pattern: Can be used to make a single class represent the identity of an entire set of related objects.

• Flyweight Pattern: Used to share objects that store their state externally. This can be helpful to conserve memory usage.

• Proxy Pattern: This can be used to ‘stand-in’ for a more complex object which will be created at a later time (very common in distributed systems).

Introduction to Design Patterns

1-10 Copyright © Intertech, Inc 2014 Rev: 2

The Creational Design Patterns

• Creational design patterns are used to simplify how complex objects are assembled in memory.

• The ultimate goal of any creational pattern is to encapsulate complex object creation for the caller.

• The GOF book has identified five common creational patterns, briefly detailed here:

• Abstract Factory Pattern: Groups together multiple object factories that have a common theme.

• Builder Pattern: Constructs complex objects by separating construction and representation.

• Factory Method Pattern: Creates objects without specifying the exact class to create.

• Prototype Pattern: Creates objects by cloning an existing object.

• Singleton Pattern: Restricts object creation for a class to only one instance.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-11

The Behavioral Design Patterns

• Behavioral design patterns are concerned with how objects in memory communicate.

• Out of all three categories, the behavioral category contains the most members.

• The “Gang of Four” have identified eleven behavioral patterns, briefly detailed here:

• Chain of Responsibility Pattern: Defines a standard way of passing a request between a related set (aka, a chain) of objects.

• Command Pattern: Creates objects which encapsulate actions and parameters (for example, Cut, Copy, Paste functionality).

• Interpreter Pattern: A way to include unique language elements in a program.

• Iterator Pattern: Allows a way to access sub-elements of an object sequentially without exposing its underlying representation.

• Mediator Pattern: Defines simplified (loosely coupled) communication between classes.

• Memento Pattern: Provides the ability to restore an object to its previous state (very common for ‘undo’ operations).

• Observer Pattern: A publish/subscribe pattern which allows a number of observer objects to see an event.

• State Pattern: Allows an object to alter its behavior when it’s internal state changes.

• Strategy Pattern: Allows one of a family of algorithms to be selected on-the-fly at runtime.

• Template Method Pattern: Defines the skeleton of an algorithm as an abstract class, allowing its subclasses to provide concrete behavior.

• Visitor Pattern: Defines a new operation to a class without change.

Introduction to Design Patterns

1-12 Copyright © Intertech, Inc 2014 Rev: 2

A Brief Review of UML

• Now that you have been given a brief overview of the 23 classic design patterns, let’s review the key UML notation which will be used to describe them.

• As mentioned, to keep a design pattern as agnostic as possible, they are described in terms of UML diagrams.

• However, in addition to a given UML diagram, a proper pattern explanation will also be explained via code, using a given programming language.

• UML is a simple notation system which allows us to diagram a software subsystem.

• UML is only concerned with relationships between the items under examination.

• UML is *not* concerned with implementation details.

• Keep in mind that a single UML diagram seldom represents an entire software application.

• Again, the diagram is typically used to model a subset of a larger system.

• As well, within a given UML subsystem diagram, it is not required to list all members of a given item.

• Rather, a UML diagram tries to capture the members which are important for the current discussion.

• For example, a UML class icon may only show 3 of 20 data members, and 2 of 40 methods.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-13

• The following table documents the core UML Icons used in this course.

• These types could be considered the building blocks of any UML diagram.

• If a pattern makes use of language specific features (e.g., .NET events), they will be examined during relevant labs.

• If you wish to see a complete listing of UML notation, consult the following web link: http://www.omg.org/gettingstarted/what_is_uml.htm.

UML Icon Meaning in Life

Represents a class in the system.

The top box is the name of the class.

The middle box lists out the relevant data fields of the class.

The bottom box lists the relevant methods, and may list parameters and return values.

Note that member visibility is denoted as:

+ Public

- Private

# Protected

Represents an interface in the system.

Notice that italicized members denote abstraction.

Abstract members in a class (or an abstract class) are also italicized.

Represents a ‘package’, meaning a collection of types which are grouped together.

.NET developers could consider a package as a custom namespace / dedicated .NET assembly.

Java developers could consider a package as a literal Java package.

UML diagrams can contain any number of notes, which help describe the overall software subsystem.

They have no direct mapping to the related code base.

Introduction to Design Patterns

1-14 Copyright © Intertech, Inc 2014 Rev: 2

• The following table documents the core UML relationship icons used in this class.

• UML proper provides additional icons for additional relationships.

• If a pattern requires additional UML relationship icons, they will be pointed out at that time.

UML Icon Meaning in Life

Represents classical inheritance; the Is-A relationship.

Represents interface implementation; the Can-Do relationship (also known as ‘realization’).

Represents the Has-A relationship.

When this UML icon using a black diamond (seen here) you are denoting ‘composition’, meaning the contained object’s lifetime dependent on the containing object.

If the same UML icon has a white diamond (not shown) you are denoting ‘aggregation’, meaning the contained object could outlive the containing object.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-15

• To see some of these UML elements working together, consider the following diagram.

• Here, StreamWriter Has-A Stream, where Stream is abstract (note italic).

• MemoryStream Is-A Stream.

• Similar relationships are also found in the diagram (BinaryReader Has-A Stream, FileStream Is-A Stream, etc).

Introduction to Design Patterns

1-16 Copyright © Intertech, Inc 2014 Rev: 2

A First Look at Patterns: The Strategy Pattern (C#)

• We are now ready to examine our first pattern: the Strategy pattern.

• This pattern is a GOF classic behavioral pattern.

• Recall that behavioral patterns are concerned with simplifying the communication between objects in memory.

• More specifically, behavioral patterns tend to focus on making complex algorithms more modular to simplify object communications.

• The Strategy pattern provides a way to extract a set of related algorithms from a single class, and isolate them into separate classes.

• By extracting algorithms into isolated classes, you provide a way the client to pick a given algorithm for performing the action.

• As a result, the Strategy pattern makes it very easy to add new algorithms over time with minimal impact to your code base.

• When using the Strategy pattern, you can simplify the coding of the class which requires multiple ways to process any related data.

• If all algorithms were placed in a single class, you would no doubt need to make use of nested if/else statements, switching logic and other conditional statements.

• If new algorithms need to be added, you would need to add even more conditional logic, which could quickly result in a maintenance nightmare.

• The Strategy pattern also allows for a clean separation of concerns, as the algorithm is decoupled from the data it operates on.

• This can help facilitate reuse of the algorithm when you require it.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-17

• To illustrate, assume you have a class named TextContainer which maintains a set of string literals.

• This class has two algorithms (aka, strategies) which can be used to display the string data; specifically ‘as declared’ and in reverse ordering.

• In the following C# implementation, notice that both algorithms are baked into a single class.

// C# code example.

class TextContainer

{

// This is the data we want to process.

private string[] strData =

{"We", "are", "family", "all", "my",

"brothers", "sisters", "and", "me"};

// The data can be displayed in one of two ways,

// use a .NET enum to represent each possibility.

public enum DisplayMode { Reverse, Normal }

// Data field to set display mode.

public DisplayMode Mode = DisplayMode.Normal;

// Show the data, based on Mode property setting.

public void Display()

{

switch (Mode)

{

// Alg 1.

case DisplayMode.Reverse:

foreach (string s in strData.Reverse())

{

Console.Write(" {0} ", s);

}

Console.WriteLine();

break;

// Alg 2.

case DisplayMode.Normal:

foreach (string s in strData)

{

Console.Write(" {0} ", s);

}

Console.WriteLine();

break;

default:

break;

}

}

}

Introduction to Design Patterns

1-18 Copyright © Intertech, Inc 2014 Rev: 2

• At this point, the caller could create an instance of the TextContainer class and make use of each algorithm as so:

• Note it is the Mode field which allows for algorithm flipping.

static void Main(string[] args)

{

// Default display is DisplayMode.Normal.

TextContainer tc = new TextContainer();

tc.Display();

// Change mode to DisplayMode.Reverse.

tc.Mode = TextContainer.DisplayMode.Reverse;

tc.Display();

}

• Here is the output from the previous example.

• Again recall, DisplayMode.Normal is the default setting.

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-19

• Now, what if you need to create new algorithms to display the data in additional ways?

• Uppercase? Alphabetical? Only words which contain vowels? Only words which contain capital letters?

• To do so, you would need to update the enum data type and add additional case blocks to your switch statement.

• Overtime, the TextContainer class could become a very hard to maintain mess, especially the Display() method.

• Consider the following code snippet…

public void Display()

{

switch (Mode)

{

case DisplayMode.Reverse:

// Code for reverse...

break;

case DisplayMode.Normal:

// Code for normal...

break;

case DisplayMode.UpperCase:

// Code for upper case...

break;

case DisplayMode.OnlyVowels:

// Code for only words with vowels...

break;

case DisplayMode.WordsWithCaps:

// Code for only words with capital letters...

break;

// Even more case statements...

default:

break;

}

}

Introduction to Design Patterns

1-20 Copyright © Intertech, Inc 2014 Rev: 2

• Even if you were to update the TextContainer class with the necessary modifications, the current solution has a few limitations:

• Other parts of your application can’t leverage these algorithms for their own data!

• Therefore, if other classes needed to sort string data in a similar way, they would need to repeat the same logic found in the Display() method.

• Ideally, we could isolate the algorithms for processing string data, to maximize reuse across projects.

• Let’s refactor this code to make use of the Strategy pattern.

• The first step is to define an interface or abstract base class which represents the overall behavior of the algorithm.

• In our example, the nature of the algorithm would be simply ‘displaying text data in a given manner’.

• The method which represents this behavior takes a reference to the object containing the data to process (TextContainer in our example).

// Remember! We could also use an ABC (abstract base class)

// rather than a custom interface.

interface IDisplayTextStrategy

{

void Display(TextContainer txtData);

}

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-21

• The TextContainer class will need to provide a way to provide / obtain the internal array of strings.

• Assume we have created a new .NET property named StringData for this purpose.

• Also notice we have kept the initial string array initialization as a ‘default’ set of data points.

class TextContainer

{

// This is the default data we want to process.

private string[] strData =

{" We ", " are ", " family ", " all ", " my ",

" brothers ", " sisters ", " and ", " me "};

// This new property allows the strategy class

// to get the data.

public string[] StringData

{

get { return strData; }

set { strData = value; }

}

...

}

Introduction to Design Patterns

1-22 Copyright © Intertech, Inc 2014 Rev: 2

• Next, we create unique classes which implement this interface, and process the incoming method data in an appropriate manner.

• This would be the OO equivalent of our previous switch logic.

• Because the algorithms are isolated in strongly typed classes, we no longer have need for a custom enumeration.

• Assume the previous DisplayMode enum has been removed from the TextContainer class.

class ReverseTextStrategy : IDisplayTextStrategy

{

public void Display(TextContainer txtData)

{

foreach (string s in txtData.StringData.Reverse())

{

Console.Write(" {0} ", s);

}

Console.WriteLine();

}

}

class NormalTextStrategy : IDisplayTextStrategy

{

public void Display(TextContainer txtData)

{

foreach (string s in txtData.StringData)

{

Console.Write(" {0} ", s);

}

Console.WriteLine();

}

}

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-23

• Finally, we can clean up the original TextContainer class as so:

• Declare a member variable of the interface / ABC type.

• Add a public member (constructor, property, method) which allows the caller to set this member variable.

• Strip out the previous conditional logic, and use the member variable to process the data.

• Here is one possible implementation.

class TextContainer

{

private string[] strData =

{" We ", " are ", " family ", " all ", " my ",

" brothers ", " sisters ", " and ", " me "};

public string[] StringData

{

get { return strData; }

set { strData = value; }

}

// This new member variable can hold a ref

// to any class implementing IDisplayTextStrategy.

IDisplayTextStrategy iftDisplayStrat = null;

// Two ways to set the strategy.

public TextContainer(IDisplayTextStrategy strat)

{

iftDisplayStrat = strat;

}

public IDisplayTextStrategy DisplayStrategy

{

set { iftDisplayStrat = value; }

}

// Now use the IDisplayTextStrategy ref to process data.

public void Display()

{

iftDisplayStrat.Display(this);

}

}

Introduction to Design Patterns

1-24 Copyright © Intertech, Inc 2014 Rev: 2

• The client could make use of this new implementation as so:

• When we create the TextContainer, we specify the ‘normal’ strategy via a constructor argument.

• Later, we change the strategy using the DisplayStrategy property.

static void Main(string[] args)

{

TextContainer tc = new TextContainer(new NormalTextStrategy());

tc.Display();

tc.DisplayStrategy = new ReverseTextStrategy();

tc.Display();

}

• So what have we gained by applying the Strategy pattern? Essentially:

• Because the data is decoupled from the logic that displays it, we can easily define new strategies to manipulate the data.

• The container of the data has no need to be updated.

• Other classes can use these strategy classes to manipulate their own string data.

• Notice how cleanly we can quickly account for new ways to manipulate data in a modular manner:

• Here is an algorithm which allows you to display the data in all upper case.

class UpperCaseTextStrategy : IDisplayTextStrategy

{

public void Display(TextContainer txtData)

{

foreach (string s in txtData.StringData)

{

Console.Write(" {0} ", s.ToUpper());

}

Console.WriteLine();

}

}

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-25

• Our Main() method could use this new strategy as so:

• The following output shows how each strategy can be used to manipulate the same string data.

static void Main(string[] args)

{

TextContainer tc = new TextContainer( new NormalTextStrategy());

tc.Display();

...

tc.DisplayStrategy = new UpperCaseTextStrategy();

tc.Display();

}

• The Strategy pattern can be formalized using the following UML diagram:

• Try to map the TextContainer, IDisplayTextStrategy, ReverseTextStrategy and NormalTextStrategy to their respective roles.

• Now, let’s see this same pattern applied in VB.NET and Java.

• As you might expect, the overall structure of the following examples will be very similar to the previous C# example…

Introduction to Design Patterns

1-26 Copyright © Intertech, Inc 2014 Rev: 2

The Strategy Pattern (VB)

• Because VB.NET makes use of the same Common Type System as C#, the following code base is very straightforward.

• The only major difference is keyword usage.

• Here would be the strategy interface and strategy classes in the syntax of VB.

Interface IDisplayTextStrategy

Sub Display(txtData As TextContainer)

End Interface

Class ReverseTextStrategy

Implements IDisplayTextStrategy

Public Sub Display(txtData As TextContainer) Implements IDisplayTextStrategy.Display

For Each s As String In txtData.StringData.Reverse()

Console.Write(" {0} ", s)

Next

Console.WriteLine()

End Sub

End Class

Class NormalTextStrategy

Implements IDisplayTextStrategy

Public Sub Display(txtData As TextContainer) Implements IDisplayTextStrategy.Display

For Each s As String In txtData.StringData

Console.Write(" {0} ", s)

Next

Console.WriteLine()

End Sub

End Class

Class UpperCaseTextStrategy

Implements IDisplayTextStrategy

Public Sub Display(txtData As TextContainer) Implements IDisplayTextStrategy.Display

For Each s As String In txtData.StringData

Console.Write(" {0} ", s.ToUpper())

Next

Console.WriteLine()

End Sub

End Class

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-27

• The TextContainer class is also straightforward:

Class TextContainer

' This is the default data we want to process.

Private strData As String() = {" We ", " are ", " family ", _

" all ", " my ", " brothers ", " sisters ", " and ", " me "}

' This new property allows the strategy class

' to get the data.

Public Property StringData() As String()

Get

Return strData

End Get

Set(ByVal value As String())

strData = value

End Set

End Property

' This new member variable can hold a ref

' to any class implementing IDisplayTextStrategy.

Private iftDisplayStrat As IDisplayTextStrategy = Nothing

Public WriteOnly Property DisplayStrategy() As IDisplayTextStrategy

Set(ByVal value As IDisplayTextStrategy)

iftDisplayStrat = value

End Set

End Property

Public Sub New(strat As IDisplayTextStrategy)

iftDisplayStrat = strat

End Sub

' Now use the IDisplayTextStrategy ref to process data.

Public Sub Display()

iftDisplayStrat.Display(Me)

End Sub

End Class

• Last but not least, a Main() method to drive the example:

• The output would be identical to the previous C# example.

Sub Main()

Dim tc As New TextContainer(New NormalTextStrategy())

tc.Display()

tc.DisplayStrategy = New ReverseTextStrategy()

tc.Display()

tc.DisplayStrategy = New UpperCaseTextStrategy()

tc.Display()

End Sub

Introduction to Design Patterns

1-28 Copyright © Intertech, Inc 2014 Rev: 2

The Strategy Pattern (Java)

• Not surprisingly, the Java code is very similar to the C# code base, as both Java and C# belong to the C family of languages.

• The only major difference is the use of traditional getters / setters, in-place of .NET property syntax.

• As well, we will ditch the “I” prefix to our interface, to be more instep with Java naming conventions.

interface DisplayTextStrategy

{

void Display(TextContainer txtData);

}

class NormalTextStrategy implements DisplayTextStrategy

{

public void Display(TextContainer txtData)

{

for (String s : txtData.getStringData())

{

System.out.print(s);

}

System.out.println();

}

}

class UpperCaseTextStrategy implements DisplayTextStrategy

{

public void Display(TextContainer txtData)

{

for (String s : txtData.getStringData())

{

System.out.print(s.toUpperCase());

}

System.out.println();

}

}

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-29

• The TextContainer and related main() method could be realized as so:

class TextContainer

{

// This is the data we want to process.

private String[] strData =

{" We ", " are ", " family ", " all ", " my ",

" brothers ", " sisters ", " and ", " me "};

// This new property allows the strategy class

// to get the data.

public String[] getStringData()

{ return strData; }

public void setStringData(String[] strs)

{ strData = strs; }

// This new member variable can hold a ref

// to any class implementing DisplayTextStrategy.

DisplayTextStrategy iftDisplayStrat = null;

public void setDisplayStrategy(DisplayTextStrategy strat)

{ iftDisplayStrat = strat; }

public TextContainer(DisplayTextStrategy strat)

{ iftDisplayStrat = strat; }

// Now use the DisplayTextStrategy ref to process data.

public void Display()

{

iftDisplayStrat.Display(this);

}

}

public static void main(String[] args) {

TextContainer tc = new TextContainer( new NormalTextStrategy());

tc.Display();

tc.setDisplayStrategy(new UpperCaseTextStrategy());

tc.Display();

}

Introduction to Design Patterns

1-30 Copyright © Intertech, Inc 2014 Rev: 2

The Nature of Intertech’s Complete Design Patterns Class

• As illustrated in the previous examination of the Strategy pattern, it can become quite tedious for students to view the same pattern via multiple languages (C#, Java, VB).

• As well, one cannot assume all Java programmers want to learn about C# extension methods or VB XML literal syntax.

• Furthermore, C# / VB developers will gain little from diving into the details of Java-specific APIs to illustrate a pattern’s implementation.

• To keep the flow of the course as clean as possible, the remainder of the lecture material will be presented as so:

• Content will focus on the classic GOF patterns, as they can be useful regardless of what type of application you are building (web app, desktop app, etc).

• Patterns will be described using UML notation, with a proper introduction as to why the pattern is useful, when you might want to apply it and any associated pitfalls.

• Lecture notes will *not* illustrate the implementation of each pattern using multiple languages (e.g., “In Java you do this, in C# you do that, in VB you do this….”).

• Rather, this course will rotate between C#, Java and VB.

• Even if a given pattern is illustrated in a language other than your personal preference, you should have no problems following along during lecture time.

• However, the labs of this course will be presented as so:

• Each student has received a Java or .NET (C#/VB) lab book, based on their platform preference.

• Here you will have a chance to work with a given pattern using your language of choice.

• As well, the labs will point out any language specific shortcuts (keywords, base classes, standard interfaces, etc) for a pattern, if appropriate.

Lab Exercise: Introducing Design Patterns (the Strategy Pattern)

Introduction to Design Patterns

Copyright © Intertech, Inc 2014 Rev: 2 1-31

Chapter Summary

• Design patterns are language and platform neutral solutions to common software problems.

• The Gang of Four book (Design Patterns: Elements of Reusable Object-Oriented Software) is regarded as a seminal book on the topic of ‘classic’ patterns.

• Design patterns are described using UML notation.

• Structure design patterns are concerned with how existing classes can be combined to deliver new functionality.

• Creational design patterns are concerned with simplifying how objects are constructed in memory.

• Behavioral design patterns are concerned with simplifying object communications.

• The Strategy pattern is a behavioral pattern which allows you to isolate algorithms, in order to simplify code maintenance and client usage.