Introduction to Design Patterns First, what s a design pattern? a general reusable solution to a commonly occurring problem within a given context in software design It s not a finished design that can be transformed directly into code It is a description or template for how to solve a problem that can be used in many different situations. patterns are formalized best practices that you must implement yourself in your application Design patterns gained popularity after the book Design Patterns: Elements of Reusable Object- Oriented Software was published in 1994 by the so-called "Gang of Four" (Gamma et al.).
Structural Some Kinds of Design Patterns These ease the design by identifying a simple way to realize relationships between entities. Behavioral These identify common communication patterns between objects and realize these patterns Creational These deal with object creation mechanisms, trying to create objects in a manner suitable to the situation And there are others
The Flyweight Design Pattern The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary. This one is a structural pattern the structural relationship between specific and shared state is what is central in this pattern When do we use a flyweight? When a class has many instances and they can all be controlled identically Classic example of the Flyweight pattern: the representation of a character in a word processor Rather than each character having separate glyph objects that represent the font and formatting data, each character could have a reference to a flyweight glyph object shared by every instance of the same character in the document. Then the character itself would need only to store it's position in the document and the reference to the glyph, rather than it's entire formatting information.
The Flyweight Pattern How does it Work? http://www.oodesign.com/flyweight-pattern.html Intrinsic state is what makes a given object unique (the glpyh for a character) Extrinsic state is information that can be passed in through arguments the character s position in the document) The Flyweight interface declares methods which flyweight instances can receive and use extrinsic data. The FlyweightFactory is responsible for the creation and management of the flyweights, ensuring that they are shared properly. If the desired Flyweight isn't created yet it will create and return one. Otherwise, it will return one from the current pool of flyweights. Often it s an indexer. A ConcreteFlyweight object adds capabilities for intrinsic state. The Client is your application program
The Strategy Pattern Intent: Define a family of algorithms, encapsulate each one, and make them interchangeable. Capture the abstraction in an interface, bury implementation details in derived classes. This one is a behavioral pattern the interface idealizes the behavior http://sourcemaking.com/design_patterns/strategy Interface could be: an abstract base class In this case, we have dynamic polymorphism the method signature expectations by the client In this case, the Interface entity represents template code and the inheritance hierarchy represents static polymorphism
The Strategy Pattern How does it Work? Define an interface that is common to all aspects of some behavior This could be a pure virtual function in a base class or a template function with its parameterized signature Define algorithms specific to particular instances of that behavior These could be concrete functions that implement the base class s pure virtual function (or the parameterized code of the template function) The client code creates a context in which a specific concrete algorithm is invoked that is appropriate in the runtime context The client code makes use of a pointer to base class to refer to a derived class object and then the proper binding of concrete method to function call (or the binding to type of argument) is done at runtime http://sourcemaking.com/design_patterns/strategy
The Factory Pattern Intent: creates objects without exposing the instantiation logic to the client. refers to the newly created object through a common interface (i.e. a pointer to base) This one is a creational pattern uses <<interface>> Product Concrete Product Client creates http://www.oodesign.com/factory-pattern.html Factory ask for a new object +createproduct():product How you use it: The client needs a product, but instead of creating it directly using the new operator, it asks the factory object for a new product, and gives the info about the type of object it needs. The factory instantiates a new concrete product and then returns the newly created product (casted to abstract product class) to the client. The client uses the products as abstract products without being aware about their concrete implementation.
The Factory Pattern How does it Work? An example: You have a graphical application works with shapes. The drawing framework is the client and the shapes are the products. All the shapes are derived from an abstract Shape class (or interface) that defines abstract draw and move operations which must be implemented by the concrete shapes. Suppose that a command is selected from a menu to create a new Circle. The drawing framework receives the shape type as a string parameter and it asks the factory to create a new shape, sending the parameter received from menu. The factory creates a new Circle and returns it to the framework, as a pointer to the base abstract class Shape. Then the framework uses the pointer to base without being aware of the concrete object type. New shapes can be added without changing a single line of code in the framework (the client code that uses the shapes from the factory). uses <<interface>> Product Concrete Product Client creates Factory +createproduct():product ask for a new object http://www.oodesign.com/factory-pattern.html
When should Factory be Used? The Factory pattern allows you to create objects without being bothered by what the actual class being created is. The benefit is that the client code (calling code) can just say "give me an object that can do XYZ" without knowing what is the actual class that can do "XYZ". Use Factory when a class can't anticipate the exact class of objects it must create. a class wants its subclasses to specify the objects it creates. classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.
Let s put this to use: The Game of Set Set is a card game The object of the game is to identify a Set of 3 cards from 12 cards laid out on a table Each card has: A Color (red, green, or blue) A Symbol (oval, squiggle, or diamond) A Number (1, 2, or 3 Symbols) Shading (solid, open, or striped) A Set consists of EITHER 3 cards with the condition: each of the features is the same on each card OR is different on each card When a set is found, those cards are removed and replaced by three new cards from the deck The deck is made up of 81 distinct cards The game continues until the deck is gone
These 3 are a Set Some Examples of Sets They all have 2 ovals so they agree on Symbol and on Number They are all of different Colors They are all of different Shading L17 Feb. 24, 2010 friends and software reuse
These 3 are a Set Some Examples of Sets They all have the same Color and the same Shading They are all of different Symbols They are all of different Numbers L17 Feb. 24, 2010 friends and software reuse
What would a typical game table look like? Where are the sets? Color Number Symbol Shading L17 Feb. 24, 2010 friends and software reuse
How would we design a program to play a solitaire game of Set? What is the basic object we have to deal with? The card What are the operations that we need to do with cards? Display them on the screen Check a collection of 3 of them to see if they form a Set What do we know about the properties (features) of an individual card? There are four features: Color, Number, Symbol, Shading For a given card, these features do not change
What does this suggest as a class for card? enum Color = {red, blue, green}; class Card { public: <some methods here, not sure what yet> private: Color col; Num num; Symbol sym; Shading shade; }; What functionality is critical for the class Card? We need to be able to determine if three cards form a set This means that we need to be able to check their features for equality Two cards with squiggle symbol need to have their Symbol attributes equal Two cards with striped shading need to have their Shading attributes equal, even if one has 2 striped red ovals and the other has 3 striped green diamonds How can we do this? One solution: write an equals() method for each attribute Problem: this will work, but it is very tedious One equals() method for each of the attributes We ll need at least one constructor and a destructor And the card needs to be able to draw itself There is a simpler way to do this
How do design patterns come into play? class Card { public: Card(); Card (Color c, Num n, Symbol sy, Shading sh); draw(); private: Color col; Num num; Symbol sym; Shading shade; }; We need to look at these objects that represent the 4 attributes each Card has
Color Each card is assigned a Color This color is used for two things: To draw the symbol in a particular color To do the fill in the symbol (if solid or striped, it should be of that color, assuming a graphical world) Our base assumptions are that Color will have one of three values: Red Blue Green So we make a class Color with an attribute that indicates the color and with methods that will let us construct a Color object, set its data value, and retrieve its data value
The class Color class Color { public: Color(); Color (int c); int get_color(); void set_color(int c); bool operator == (Color &c) private: int col; } How many Color objects are we going to need? Here s where we use the flyweight!! Make 3 Color objects and let the cards share them L17 Feb. 24, 2010 friends and software reuse Color::Color() { col = 15; // default color is white } Color::Color (int c) { col = (c % 16); // color is between 0 and 15 } int Color::get_color() { return (col); } void Color::set_color(int c) { col = (c % 16); } bool Color:: operator == (Color &c) { return (col == c.col;) }
Number The Number attribute says how many Symbols are on the card In a general implementation, it also indicates where each of the symbols should be drawn If there is 1 symbol, it is in the middle If there are 2 or 3, they are centered in the card vertically The idea is that all cards with, say, 3 symbols on them will draw them in the same relative position on the card This means that it will not work to have the Number be a simple integer (1, 2, or 3). It needs to be a vector of (x,y) locations Then the number of symbols is the length of the vector How many numbers do we need? Three, so use the Flyweight here, too!!
Symbol The symbol (in a general graphical game) is a shape We could indeed think of a symbol as a string or a character What is the most important thing a symbol has to do? Know how to draw itself So its most important method would be a draw() method But each symbol will be drawn differently! That means that each symbol has to belong to its own class so that the draw method for it can be specific to it. And each card also has a shading associated with it, so the draw method should have a shading argument: draw(shading s)
Class Structure for Symbol The draw method for a Symbol is polymorphic the draw method of the base class Symbol would be a pure virtual method and the derived classes would display the proper symbol
Using the Attributes of a Card We ve discussed three of the attributes: Color Number Symbol We haven t yet talked about Shading, but that s for a reason: it can be more complicated The role of the attributes is To use in checking whether a group of 3 Cards makes a Set Turns out this is pretty easy To use when the Card draws itself The Card has to use the Color and the Number (with its vector of locations) to guide the drawing, but it s going to delegate the job of actually drawing the shapes to Symbol
Checking to see if we have a Set We can make a method for the class Card like this: bool Card::isSetSymbol (Card c1, Card c2, Card c3) { } If (c1.sym == c2.sym && c2.sym == c3.sym) (c1.sym!= c2.sym && c1.sym!= c3.sym && c2.sym!= c3.sym) return true; else return false; And we make similar methods issetnumber, issetcolor, and issetshading Then we can easily tell if a collection of 3 cards is a Set
What about drawing the card? The Card uses the Color and the Number (with its vector of locations) to guide the drawing, but remember that it s going to delegate the job of actually drawing the shapes to Symbol But remember that the concept of having an algorithm delegate responsibility for some part of its function to some helper object is called the Strategy Design Pattern This simplifies the card s draw code But to do it, we do have to define the abstract class Symbol and its derived classes Diamond, Oval, and Squiggle
Pseudocode for drawing the Card Remember that we have: Card with its private members col, num, sym, and shade The class Symbol has a draw method, and we ll let that draw method have a single argument: a Shading void Card::draw() { setcolor (col); //set the display color to the Color attribute of the Card for each( location in num) { sym.draw (shade); } }
Now let s return to the Shading feature What does this feature really DO? If the application is a graphical one, it designates the fill color and texture of the shape, once colored If open, the fill is the background color If solid, the fill is the display color If striped, the fill is a texture of the display color If the application is a console application, it has to be something else! Turns out, we can set background color and text color independently So if we have a console app, we can let the Shading determine the background color Accomplishing the task of displaying the card by using the draw method of Symbol as our work horse tool lets us hide the implementation details We make the Shading feature be represented by a base class Shading with derived classes Solid, Open, and Striped This class hierarchy has an abstract method getpaint() that each of the derived classes overrides to make the concrete class We can change the nature of the visual display easily by just changing the getpaint() methods of the Shading derived classes!
Factory Pattern This is an example of using another design pattern The Factory Pattern Remember that this pattern has an object return an instance from a family of related classes that meet this particular class s needs A factory is an object for creating other objects The idea is to define an interface (abstract class) for creating an object, but let the classes which implement the interface decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses
So how do we change colors? In Visual Studio, the text color and the background color can be (somewhat independently) set: There are 16 colors, and each has a number: BLACK = 0, BLUE = 1, GREEN = 2, CYAN = 3, RED = 4 MAGENTA = 5, BROWN = 6, LIGHTGREY = 7, DARKGREY = 8, LIGHTBLUE = 9, LIGHTGREEN = 10, LIGHTCYAN = 11, LIGHTRED = 12, LIGHTMAGENTA = 13, YELLOW = 14, WHITE =15 The color of the text and background is determined using the following formula: colorattribute = foreground + background * 16 to get red text on yellow use 4 + 14*16 = 228 light red on yellow would be 12 + 14*16 = 236 Bottom line is that you can easily write the draw method for a console application!!