Creational patterns
1. Abstract Factory
2. Builder
3. Factory Method
4. Prototype
5. Singleton
Structural patterns
6. Adapter
7. Bridge
8. Composite
9. Decorator
10. Façade
11. Flyweight
12. Proxy
Behavioral patterns
13. Chain Of Responsibility
14. Command
15. Interpreter
16. Iterator
17. Mediator
18. Memento
19. Observer
20. State
21. Strategy
22. Template
23. Visitor
Creational patterns
Abstract Factory
A way passing a request between a chain of objects
Definition
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Usage
Very high
Participants
AbstractFactory
abstract class ContinentFactory { public abstract Herbivore CreateHerbivore(); public abstract Carnivore CreateCarnivore(); } |
ConcreteFactory
class AfricaFactory : ContinentFactory { public override Herbivore CreateHerbivore() { return new Wildebeest(); } public override Carnivore CreateCarnivore() { return new Lion(); } } |
AbstractProduct
abstract class Herbivore { } abstract class Carnivore { public abstract void Eat(Herbivore h); } |
Product
class Lion : Carnivore { public override void Eat(Herbivore h) { // Eat Wildebeest Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name); } } |
Client class AnimalWorld { private Herbivore herbivore; private Carnivore carnivore; // Constructor public AnimalWorld(ContinentFactory factory) { carnivore = factory.CreateCarnivore(); herbivore = factory.CreateHerbivore(); } public void RunFoodChain() { carnivore.Eat(herbivore); } } |
public static void Main() { // Create and run the Africa animal world ContinentFactory africa = new AfricaFactory(); AnimalWorld world = new AnimalWorld(africa); world.RunFoodChain(); } |
Builder
Separates object construction from its representation
Definition
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
Usage
Medium Low
Participants
Director
class Shop { public void Construct(VehicleBuilder vehicleBuilder) { vehicleBuilder.BuildFrame(); vehicleBuilder.BuildEngine(); } } |
Builder
abstract class VehicleBuilder { protected Vehicle vehicle; // Property public Vehicle Vehicle { get{ return vehicle; } } public abstract void BuildFrame(); public abstract void BuildEngine(); } |
ConcreteBuilder
1. class MotorCycleBuilder : VehicleBuilder { public override void BuildFrame() { vehicle = new Vehicle("MotorCycle"); vehicle["frame"] = "MotorCycle Frame"; } public override void BuildEngine() { vehicle["engine"] = "500 cc"; } } 2. class CarBuilder : VehicleBuilder { public override void BuildFrame() { vehicle = new Vehicle("Car"); vehicle["frame"] = "Car Frame"; } public override void BuildEngine() { vehicle["engine"] = "2500 cc"; } } |
Product
class Vehicle { private string type; private Hashtable parts = new Hashtable(); public Vehicle(string type) { this.type = type; } public object this[string key] { get{ return parts[key]; } set{ parts[key] = value; } } public void Show() { Console.WriteLine("\n---------------------------"); Console.WriteLine("Vehicle Type: {0}", type); Console.WriteLine(" Frame : {0}", parts["frame"]); Console.WriteLine(" Engine : {0}", parts["engine"]); } } |
public static void Main() { // Create shop with vehicle builders Shop shop = new Shop(); VehicleBuilder b2 = new CarBuilder(); VehicleBuilder b3 = new MotorCycleBuilder(); // Construct and display vehicles shop.Construct(b1); b1.Vehicle.Show(); shop.Construct(b2); b2.Vehicle.Show(); } |
Factory Method
Creates an instance of several derived classes
Definition
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Usage
High
Participants
Product abstract class Page { } |
ConcreteProduct
1. class SkillsPage : Page { } 2. class EducationPage : Page { } 3. class ConclusionPage : Page { } |
Creator
abstract class Document { private ArrayList pages = new ArrayList(); public Document() { this.CreatePages(); } public ArrayList Pages { get{ return pages; } } public abstract void CreatePages(); } |
ConcreteCreator
class Resume : Document { public override void CreatePages() { Pages.Add(new SkillsPage()); Pages.Add(new EducationPage()); } } 2. class Report : Document { public override void CreatePages() { Pages.Add(new SkillsPage()); Pages.Add(new EducationPage()); Pages.Add(new ConclusionPage()); } } |
public static void Main() { Document[] documents = new Document[2]; documents[0] = new Resume(); documents[1] = new Report(); } |
Prototype
A fully initialized instance to be copied or cloned
Definition
Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.
Cloning is an important aspect of it.
Usage
Medium
Participants
Prototype
abstract class ColorPrototype { public abstract ColorPrototype Clone(); } |
ConcretePrototype
class Color : ColorPrototype { private int red; private int green; private int blue; // Constructor public Color(int red, int green, int blue) { this.red = red; this.green = green; this.blue = blue; } // Create a shallow copy public override ColorPrototype Clone() { return this.MemberwiseClone() as ColorPrototype; } } |
Client/PrototypeManager
class ColorManager { Hashtable colors = new Hashtable(); // Indexer public ColorPrototype this[string name] { get { return colors[name] as ColorPrototype; } set { colors.Add(name, value); } } } |
static void Main() { ColorManager colormanager = new ColorManager(); // Initialize with standard colors colormanager["red" ] = new Color(255, 0, 0); // User adds personalized colors colormanager["peace"] = new Color(128, 211, 128); Color color; // User uses selected colors string name = "red"; color = colormanager[name].Clone() as Color; name = "peace"; color = colormanager[name].Clone() as Color; } |
Singleton
A class of which only a single instance can be created
Definition
Ensure a class has only one instance and provide a global point of access to it.
Usage
Medium High
Participants
Singleton
class LoadBalancer { private static LoadBalancer instance; private ArrayList servers = new ArrayList(); private Random random = new Random(); // Lock synchronization object private static object syncLock = new object(); // Constructor (protected) protected LoadBalancer() { // List of available servers servers.Add("ServerI"); servers.Add("ServerII"); servers.Add("ServerIII"); } public static LoadBalancer GetLoadBalancer() { // avoids locking each time the method is invoked if (instance == null) { lock (syncLock) { if (instance == null) { instance = new LoadBalancer(); } } } return instance; } // Simple, but effective random load balancer public string Server { get { int r = random.Next(servers.Count); return servers[r].ToString(); } } } |
static void Main() { LoadBalancer b1 = LoadBalancer.GetLoadBalancer(); LoadBalancer b2 = LoadBalancer.GetLoadBalancer(); LoadBalancer b3 = LoadBalancer.GetLoadBalancer(); // Same instance? if (b1 == b2 && b2 == b3) { Console.WriteLine("Same instance\n"); } // All are the same instance -- use b1 arbitrarily - Load balance 15 server requests for (int i = 0; i < 15; i++) { Console.WriteLine(b1.Server); } } |
Structural patterns
Adapter
Match interfaces of different classes
Definition
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Usage
Medium high
Participants
Target
class Compound { protected string name; protected float boilingPoint; protected string molecularFormula; public Compound(string name) { this.name = name; } public virtual void Display() { Console.WriteLine("\nCompound: {0} ------ ", name); } } |
Adapter
class RichCompound : Compound { private ChemicalDatabank bank; public RichCompound(string name) : base(name) { } public override void Display() { // Adaptee bank = new ChemicalDatabank(); boilingPoint = bank.GetCriticalPoint(name, "B"); meltingPoint = bank.GetCriticalPoint(name, "M"); molecularFormula = bank.GetMolecularStructure(name); } } |
Adaptee
class ChemicalDatabank { // The Databank 'legacy API' public float GetCriticalPoint(string compound, string point) { float temperature = 0.0F; if (point == "M") // Melting Point { switch (compound.ToLower()) { case "water" : temperature = 0.0F; break; case "benzene" : temperature = 5.5F; break; } } else // Boiling Point { switch (compound.ToLower()) { case "water" : temperature = 100.0F; break; case "benzene" : temperature = 80.1F; break; } } return temperature; } public string GetMolecularStructure(string compound) { string structure = ""; switch (compound.ToLower()) { case "water" : structure = "H20"; break; case "benzene" : structure = "C6H6"; break; } return structure; } } |
static void Main() { // Non-adapted chemical compound Compound stuff = new Compound("Unknown"); stuff.Display(); // Adapted chemical compounds Compound water = new RichCompound("Water"); water.Display(); Compound benzene = new RichCompound("Benzene"); benzene.Display(); } |
Bridge
Separates an object's interface from its implementation
Definition
Decouple an abstraction from its implementation so that the two can vary independently.
Usage
Medium
Participants
Abstraction
class CustomersBase { private DataObject dataObject; protected string group; public CustomersBase(string group) { this.group = group; } // Property public DataObject Data { set{ dataObject = value; } get{ return dataObject; } } public virtual void Next() { dataObject.NextRecord(); } public virtual void New(string name) { dataObject.NewRecord(name); } public virtual void Show() { dataObject.ShowRecord(); } public virtual void ShowAll() { Console.WriteLine("Customer Group: " + group); dataObject.ShowAllRecords(); } } |
RefinedAbstraction
class Customers : CustomersBase { // Constructor public Customers(string group) : base(group) { } public override void ShowAll() { Console.WriteLine ("------------------------"); base.ShowAll(); Console.WriteLine ("------------------------"); } } |
Implementor
abstract class DataObject { public abstract void NextRecord(); public abstract void PriorRecord(); public abstract void NewRecord(string name); public abstract void DeleteRecord(string name); public abstract void ShowRecord(); public abstract void ShowAllRecords(); } |
ConcreteImplementor
class CustomersData : DataObject { private ArrayList customers = new ArrayList(); private int current = 0; public CustomersData() { // Loaded from a database customers.Add("Jim Jones"); customers.Add("Samual Jackson"); } public override void NextRecord() { if (current <= customers.Count - 1) { current++; } } public override void NewRecord(string name) { customers.Add(name); } public override void ShowRecord() { Console.WriteLine(customers[current]); } public override void ShowAllRecords() { foreach (string name in customers) { Console.WriteLine(" " + name); } } } |
static void Main() { // Create RefinedAbstraction Customers customers = new Customers("Chicago"); // Set ConcreteImplementor customers.Data = new CustomersData(); // Exercise the bridge customers.Show(); customers.Next(); customers.Show(); customers.Next(); customers.Show(); customers.New("Henry Velasquez"); customers.ShowAll(); // Wait for user Console.Read(); } |
Composite
A tree structure of simple and composite objects
Definition
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Usage
Medium High
Participants
Component
abstract class DrawingElement { protected string name; // Constructor public DrawingElement(string name) { this.name = name; } public abstract void Add(DrawingElement d); public abstract void Remove(DrawingElement d); public abstract void Display(int indent); } |
Leaf
class PrimitiveElement : DrawingElement { // Constructor public PrimitiveElement(string name) : base(name) { } public override void Add(DrawingElement c) { Console.WriteLine("Cannot add to a PrimitiveElement"); } public override void Remove(DrawingElement c) { Console.WriteLine("Cannot remove from a PrimitiveElement"); } public override void Display(int indent) { Console.WriteLine(new String('-', indent) + " " + name); } } |
Composite
class CompositeElement : DrawingElement { private ArrayList elements = new ArrayList(); // Constructor public CompositeElement(string name) : base(name) { } public override void Add(DrawingElement d) { elements.Add(d); } public override void Remove(DrawingElement d) { elements.Remove(d); } public override void Display(int indent) { Console.WriteLine(new String('-', indent) + "+ " + name); // Display each child element on this node foreach (DrawingElement c in elements) { c.Display(indent + 2); } } } |
static void Main() { // Create a tree structure CompositeElement root = new CompositeElement("Picture"); root.Add(new PrimitiveElement("Red Line")); root.Add(new PrimitiveElement("Blue Circle")); CompositeElement comp = new CompositeElement("Two Circles"); comp.Add(new PrimitiveElement("Black Circle")); comp.Add(new PrimitiveElement("White Circle")); root.Add(comp); // Add and remove a PrimitiveElement PrimitiveElement pe = new PrimitiveElement("Yellow Line"); root.Add(pe); root.Remove(pe); // Recursively display nodes root.Display(1); } |
Decorator
Add responsibilities to objects dynamically
Definition
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Usage
Medium
Participants
Component
abstract class LibraryItem { private int numCopies; // Property public int NumCopies { get{ return numCopies; } set{ numCopies = value; } } public abstract void Display(); } |
ConcreteComponent
1. class Book : LibraryItem { private string author; private string title; // Constructor public Book(string author,string title,int numCopies) { this.author = author; this.title = title; this.NumCopies = numCopies; } public override void Display() { Console.WriteLine("\nBook ------ "); Console.WriteLine(" Author: {0}", author); Console.WriteLine(" Title: {0}", title); Console.WriteLine(" # Copies: {0}", NumCopies); } } 2. class Video : LibraryItem { private string director; private string title; private int playTime; // Constructor public Video(string director, string title, int numCopies, int playTime) { this.director = director; this.title = title; this.NumCopies = numCopies; this.playTime = playTime; } public override void Display() { Console.WriteLine("\nVideo ----- "); Console.WriteLine(" Director: {0}", director); Console.WriteLine(" Title: {0}", title); Console.WriteLine(" # Copies: {0}", NumCopies); Console.WriteLine(" Playtime: {0}\n", playTime); } } |
Decorator
abstract class Decorator : LibraryItem { protected LibraryItem libraryItem; // Constructor public Decorator(LibraryItem libraryItem) { this.libraryItem = libraryItem; } public override void Display() { libraryItem.Display(); } } |
ConcreteDecorator
class Borrowable : Decorator { protected ArrayList borrowers = new ArrayList(); // Constructor public Borrowable(LibraryItem libraryItem) : base(libraryItem) { } public void BorrowItem(string name) { borrowers.Add(name); libraryItem.NumCopies--; } public void ReturnItem(string name) { borrowers.Remove(name); libraryItem.NumCopies++; } public override void Display() { base.Display(); foreach (string borrower in borrowers) { Console.WriteLine(" borrower: " + borrower); } } } |
static void Main() { Book book = new Book ("Worley", "Inside ASP.NET", 10); book.Display(); Video video = new Video ("Spielberg", "Jaws", 23, 92); video.Display(); // Make video borrowable, then borrow and display Borrowable borrowvideo = new Borrowable(video); borrowvideo.BorrowItem("Customer #1"); borrowvideo.BorrowItem("Customer #2"); borrowvideo.Display(); } |
Façade
A single class that represents an entire subsystem
Definition
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.
Usage
High
Participants
Subsystem
1. class Bank { public bool HasSufficientSavings(Customer c, int amount) { Console.WriteLine("Check bank for " + c.Name); return true; } } 2. class Loan { public bool HasNoBadLoans(Customer c) { Console.WriteLine("Check loans for " + c.Name); return true; } } 3. class Customer { private string name; public Customer(string name) { this.name = name; } public string Name { get{ return name; } } } |
Facade
class Mortgage { private Bank bank = new Bank(); private Loan loan = new Loan(); public bool IsEligible(Customer cust, int amount) { Console.WriteLine("{0} applies for {1:C} loan\n",cust.Name, amount); bool eligible = true; // Check creditworthyness of applicant if (!bank.HasSufficientSavings(cust, amount)) { eligible = false; } else if (!loan.HasNoBadLoans(cust)) { eligible = false; } return eligible; } } |
static void Main() { Mortgage mortgage = new Mortgage(); // Evaluate mortgage eligibility for customer Customer customer = new Customer("Ann McKinsey"); bool eligable = mortgage.IsEligible(customer,125000); Console.WriteLine("\n" + customer.Name + " has been " + (eligable ? "Approved" : "Rejected")); } |
Flyweight
A friend-grained instance used for efficient sharing
Definition
Use sharing to support large numbers of fine-grained objects efficiently.
Usage
Low
Participants
FlyweightFactory
class CharacterFactory { private Hashtable characters = new Hashtable(); public Character GetCharacter(char key) { Character character = characters[key] as Character; if (character == null) { switch (key) { case 'A': character = new CharacterA(); break; case 'B': character = new CharacterB(); break; //... case 'Z': character = new CharacterZ(); break; } characters.Add(key, character); } return character; } } |
Flyweight
abstract class Character { protected char symbol; protected int width; protected int height; protected int pointSize; public abstract void Display(int pointSize); } |
ConcreteFlyweight
1. class CharacterA : Character { // Constructor public CharacterA() { this.symbol = 'A'; this.height = 100; this.width = 120; } public override void Display(int pointSize) { this.pointSize = pointSize; Console.WriteLine(this.symbol + " (pointsize " + this.pointSize + ")"); } } 2. class CharacterB : Character { // Constructor public CharacterB() { this.symbol = 'B'; this.height = 100; this.width = 140; } public override void Display(int pointSize) { this.pointSize = pointSize; Console.WriteLine(this.symbol + " (pointsize " + this.pointSize + ")"); } } |
static void Main() { // Build a document with text string document = "AABBAB"; char[] chars = document.ToCharArray(); CharacterFactory f = new CharacterFactory(); int pointSize = 10; // For each character use a flyweight object foreach (char c in chars) { pointSize++; Character character = f.GetCharacter(c); character.Display(pointSize); } } |
Proxy
An object representing another object
Definition
Provide a surrogate or placeholder for another object to control access to it.
Usage
Medium High
Participants
Subject
public interface IMath { double Add(double x, double y); double Sub(double x, double y); } |
RealSubject
class Math : IMath { public double Add(double x, double y){return x + y;} public double Sub(double x, double y){return x - y;} } |
Proxy
class MathProxy : IMath { Math math; public MathProxy() { math = new Math(); } public double Add(double x, double y) { return math.Add(x,y); } public double Sub(double x, double y) { return math.Sub(x,y); } } |
static void Main() { // Create math proxy MathProxy p = new MathProxy(); // Do the math Console.WriteLine("4 + 2 = " + p.Add(4, 2)); Console.WriteLine("4 - 2 = " + p.Sub(4, 2)); } |
Behavioral patterns
Chain Of Responsibility
A way passing a request between a chain of objects
Definition
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
Usage
Medium Low
Participants
Handler
abstract class Approver { protected Approver successor; public void SetSuccessor(Approver successor) { this.successor = successor; } public abstract void ProcessRequest(Purchase purchase); } |
ConcreteHandler
1. class Director : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 10000.0) { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest(purchase); } } } 2. class VicePresident : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 25000.0) { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest(purchase); } } } 3. class President : Approver { public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 100000.0) { Console.WriteLine("{0} approved request# {1}", this.GetType().Name, purchase.Number); } else { Console.WriteLine("Request# {0} requires an executive meeting!", purchase.Number); } } } Responsibility Details class Purchase { public int number; public double amount; public string purpose; // Constructor public Purchase(int number, double amount, string purpose) { this.number = number; this.amount = amount; this.purpose = purpose; } } |
static void Main() { // Setup Chain of Responsibility Director Larry = new Director(); VicePresident Sam = new VicePresident(); President Tammy = new President(); Larry.SetSuccessor(Sam); Sam.SetSuccessor(Tammy); Purchase p = new Purchase(2034, 350.00, "Supplies"); Larry.ProcessRequest(p); p = new Purchase(2035, 32590.10, "Project X"); Larry.ProcessRequest(p); } |
Command
Encapsulate a command request as an object
Definition
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Usage
Medium High
Participants
Command
abstract class Command { public abstract void Execute(); public abstract void UnExecute(); } |
ConcreteCommand
class CalculatorCommand : Command { char @operator; int operand; Calculator calculator; public CalculatorCommand(Calculator calculator, char @operator, int operand) { this.calculator = calculator; this.@operator = @operator; this.operand = operand; } public char Operator { set{ @operator = value; } } public int Operand { set{ operand = value; } } public override void Execute() { calculator.Operation(@operator, operand); } public override void UnExecute() { calculator.Operation(Undo(@operator), operand); } private char Undo(char @operator) { char undo; switch(@operator) { case '+': undo = '-'; break; case '-': undo = '+'; break; case '*': undo = '/'; break; case '/': undo = '*'; break; default : undo = ' '; break; } return undo; } } |
Receiver
class Calculator { private int curr = 0; public void Operation(char @operator, int operand) { switch(@operator) { case '+': curr += operand; break; case '-': curr -= operand; break; case '*': curr *= operand; break; case '/': curr /= operand; break; } Console.WriteLine("Current value = {0,3} (following {1} {2})", curr, @operator, operand); } } |
Invoker
class User { private Calculator calculator = new Calculator(); private ArrayList commands = new ArrayList(); private int current = 0; public void Undo(int levels) { for (int i = 0; i < levels; i++) { if (current > 0) { Command command = commands[--current] as Command; command.UnExecute(); } } } public void Compute(char @operator, int operand) { Command command = new CalculatorCommand(calculator, @operator, operand); command.Execute(); commands.Add(command); current++; } } |
static void Main() { User user = new User(); user.Compute('+', 100); user.Compute('-', 50); user.Compute('*', 10); user.Compute('/', 2); // Undo 4 commands user.Undo(2); } |
Interpreter
A way to include language elements in a program
Definition
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
Usage
Low
Participants
Context
class Context { private string input; private int output; public Context(string input) { this.input = input; } } |
AbstractExpression
abstract class Expression { public void Interpret(Context context) { if (context.Input.Length == 0) return; if (context.Input.StartsWith(Nine())) { context.Output += (9 * Multiplier()); context.Input = context.Input.Substring(2); } else if (context.Input.StartsWith(Four())) { context.Output += (4 * Multiplier()); context.Input = context.Input.Substring(2); } else if (context.Input.StartsWith(Five())) { context.Output += (5 * Multiplier()); context.Input = context.Input.Substring(1); } while (context.Input.StartsWith(One())) { context.Output += (1 * Multiplier()); context.Input = context.Input.Substring(1); } } public abstract string One(); public abstract string Four(); public abstract string Five(); public abstract string Nine(); public abstract int Multiplier(); } |
TerminalExpression
1. class ThousandExpression : Expression { public override string One() { return "M"; } public override string Four(){ return " "; } public override string Five(){ return " "; } public override string Nine(){ return " "; } public override int Multiplier() { return 1000; } } 2. class HundredExpression : Expression { public override string One() { return "C"; } public override string Four(){ return "CD"; } public override string Five(){ return "D"; } public override string Nine(){ return "CM"; } public override int Multiplier() { return 100; } } 3. class TenExpression : Expression { public override string One() { return "X"; } public override string Four(){ return "XL"; } public override string Five(){ return "L"; } public override string Nine(){ return "XC"; } public override int Multiplier() { return 10; } } 4. class OneExpression : Expression { public override string One() { return "I"; } public override string Four(){ return "IV"; } public override string Five(){ return "V"; } public override string Nine(){ return "IX"; } public override int Multiplier() { return 1; } } |
static void Main() { string roman = "MCMXXVIII"; Context context = new Context(roman); ArrayList tree = new ArrayList(); tree.Add(new ThousandExpression()); tree.Add(new HundredExpression()); tree.Add(new TenExpression()); tree.Add(new OneExpression()); foreach (Expression exp in tree) { exp.Interpret(context); } Console.WriteLine("{0} = {1}", roman, context.Output); } |
Iterator
Sequentially access the elements of a collection
Definition
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Usage
High
Participants
Aggregate
interface IAbstractCollection { Iterator CreateIterator(); } |
ConcreteAggregate
class Collection : IAbstractCollection { private ArrayList items = new ArrayList(); public Iterator CreateIterator() { return new Iterator(this); } // Property public int Count { get{ return items.Count; } } // Indexer public object this[int index] { get{ return items[index]; } set{ items.Add(value); } } } |
Iterator
interface IAbstractIterator { Item First(); Item Next(); bool IsDone{ get; } Item CurrentItem{ get; } } |
ConcreteIterator
class Iterator : IAbstractIterator { private Collection collection; private int current = 0; private int step = 1; public Iterator(Collection collection) { this.collection = collection; } public Item First() { current = 0; return collection[current] as Item; } public Item Next() { current += step; if (!IsDone) return collection[current] as Item; else return null; } public int Step { get{ return step; } set{ step = value; } } public Item CurrentItem { get { return collection[current] as Item; } } public bool IsDone { get { return current >= collection.Count ? true : false; } } } |
static void Main() { // Build a collection Collection collection = new Collection(); collection[0] = new Item("Item 0"); collection[1] = new Item("Item 1"); collection[2] = new Item("Item 2"); Iterator iterator = new Iterator(collection); iterator.Step = 2; for(Item item = iterator.First(); !iterator.IsDone; item = iterator.Next()) { Console.WriteLine(item.Name); } } |
Mediator
Defines simplified communication between classes
Definition
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Usage
Medium Low
Participants
Mediator
abstract class AbstractChatroom { public abstract void Register(Participant participant); public abstract void Send( string from, string to, string message); } |
ConcreteMediator
class Chatroom : AbstractChatroom { private Hashtable participants = new Hashtable(); public override void Register(Participant participant) { if (participants[participant.Name] == null) { participants[participant.Name] = participant; } participant.Chatroom = this; } public override void Send(string from, string to, string message) { Participant pto = (Participant)participants[to]; if (pto != null) { pto.Receive(from, message); } } } |
Colleague
class Participant { private Chatroom chatroom; private string name; public Participant(string name) { this.name = name; } public string Name { get{ return name; } } public Chatroom Chatroom { set{ chatroom = value; } get{ return chatroom; } } public void Send(string to, string message) { chatroom.Send(name, to, message); } public virtual void Receive(string from, string message) { Console.WriteLine("{0} to {1}: '{2}'", from, Name, message); } } |
static void Main() { Chatroom chatroom = new Chatroom(); Participant George = new Participant("George"); Participant John= new Participant("John"); chatroom.Register(George); chatroom.Register(John); George.Send ("John", "Hi John!"); John.Send("George", "My sweet Lord"); George.Send ("John", "Can't buy me love"); } |
Memento
Capture and restore an object's internal state
Definition
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
Usage
Low
Participants
Originator
class SalesProspect { private string name; private string phone; private double budget; public string Name { get{ return name; } set { name = value; Console.WriteLine("Name: " + name); } } public string Phone { get{ return phone; } set { phone = value; Console.WriteLine("Phone: " + phone); } } public double Budget { get{ return budget; } set { budget = value; Console.WriteLine("Budget: " + budget); } } public Memento SaveMemento() { Console.WriteLine("\nSaving state --\n"); return new Memento(name, phone, budget); } public void RestoreMemento(Memento memento) { Console.WriteLine("\nRestoring state --\n"); this.Name = memento.Name; this.Phone = memento.Phone; this.Budget = memento.Budget; } } |
Memento
class Memento { private string name; private string phone; private double budget; public Memento(string name, string phone, double budget) { this.name = name; this.phone = phone; this.budget = budget; } public string Name { get{ return name; } set{ name = value; } } public string Phone { get{ return phone; } set{ phone = value; } } public double Budget { get{ return budget; } set{ budget = value; } } } |
Caretaker
class ProspectMemory { private Memento memento; public Memento Memento { set{ memento = value; } get{ return memento; } } } |
static void Main() { SalesProspect s = new SalesProspect(); s.Name = "Noel van Halen"; s.Phone = "(412) 256-0990"; s.Budget = 25000.0; // Store internal state ProspectMemory m = new ProspectMemory(); m.Memento = s.SaveMemento(); // Continue changing originator s.Name = "Leo Welch"; s.Phone = "(310) 209-7111"; s.Budget = 1000000.0; // Restore saved state s.RestoreMemento(m.Memento); } |
Observer
A way of notifying change to a number of classes
Definition
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Usage
High
Participants
Subject
abstract class Stock { protected string symbol; protected double price; private ArrayList investors = new ArrayList(); public Stock(string symbol, double price) { this.symbol = symbol; this.price = price; } public void Attach(Investor investor) { investors.Add(investor); } public void Notify() { foreach (Investor investor in investors) { investor.Update(this); } Console.WriteLine(""); } public double Price { get{ return price; } set { price = value; Notify(); } } public string Symbol { get{ return symbol; } set{ symbol = value; } } } |
ConcreteSubject
class IBM : Stock { // Constructor public IBM(string symbol, double price) : base(symbol, price) { } } |
Observer
interface IInvestor { void Update(Stock stock); } |
ConcreteObserver
class Investor : IInvestor { private string name; private Stock stock; public Investor(string name) { this.name = name; } public void Update(Stock stock) { Console.WriteLine("Notified {0} of {1}'s change to {2:C}", name, stock.Symbol, stock.Price); } public Stock Stock { get{ return stock; } set{ stock = value; } } } |
static void Main() { // Create investors Investor s = new Investor("Sorros"); Investor b = new Investor("Berkshire"); // Create IBM stock and attach investors IBM ibm = new IBM("IBM", 120.00); ibm.Attach(s); ibm.Attach(b); ibm.Price = 120.10; ibm.Price = 121.00; } |
State
Alter an object's behavior when its state changes.
Definition
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
Usage
Medium
Participants
State
abstract class State { public Account account; public double balance; protected double interest; protected double lowerLimit; protected double upperLimit; public abstract void Deposit(double amount); public abstract void Withdraw(double amount); } |
ConcreteState
class SilverState : State { public SilverState(State state) : this( state.Balance, state.Account) { } public SilverState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { interest = 0.0; lowerLimit = 0.0; upperLimit = 1000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } private void StateChangeCheck() { if (balance > upperLimit) { account.State = new GoldState(this); } } } 2. class GoldState : State { // Overloaded constructors public GoldState(State state) : this(state.Balance,state.Account) { } public GoldState(double balance, Account account) { this.balance = balance; this.account = account; Initialize(); } private void Initialize() { interest = 0.05; lowerLimit = 1000.0; upperLimit = 10000000.0; } public override void Deposit(double amount) { balance += amount; StateChangeCheck(); } public override void Withdraw(double amount) { balance -= amount; StateChangeCheck(); } private void StateChangeCheck() { if (balance < lowerLimit) { account.State = new SilverState(this); } } } |
Context
class Account { private State state; private string owner; public Account(string owner) { // New accounts are 'Silver' by default this.owner = owner; state = new SilverState(0.0, this); } public double Balance { get{ return state.Balance; } } public State State { get{ return state; } set{ state = value; } } public void Deposit(double amount) { state.Deposit(amount); Console.WriteLine(" Balance = {0:C}", this.Balance); } public void Withdraw(double amount) { state.Withdraw(amount); Console.WriteLine(" Balance = {0:C}", this.Balance); } } |
static void Main() { // Open a new account Account account = new Account("Jim Johnson"); account.Deposit(500.0); account.Deposit(300.0); account.Withdraw(1100.00); } |
Strategy
Encapsulates an algorithm inside a class
Definition
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Usage
Medium High
Participants
Strategy
abstract class SortStrategy { public abstract void Sort(ArrayList list); } |
ConcreteStrategy
1. class QuickSort : SortStrategy { public override void Sort(ArrayList list) { list.Sort(); // Default is Quicksort Console.WriteLine("QuickSorted list "); } } 2. class ShellSort : SortStrategy { public override void Sort(ArrayList list) { Console.WriteLine("ShellSorted list "); } } |
Context
class SortedList { private ArrayList list = new ArrayList(); 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); foreach (string name in list) { Console.WriteLine(" " + name); } } } |
static void Main() { SortedList studentRecords = new SortedList(); studentRecords.Add("Samual"); studentRecords.Add("Jimmy"); studentRecords.Add("Sandra"); studentRecords.SetSortStrategy(new QuickSort()); studentRecords.Sort(); studentRecords.SetSortStrategy(new MergeSort()); studentRecords.Sort(); } |
Template
Defer the exact steps of an algorithm inside a class
Definition
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.
Usage
Medium
Participants
AbstractClass
abstract class DataAccessObject { protected string connectionString; protected DataSet dataSet; public virtual void Connect() { connectionString = "provider=Microsoft.JET.OLEDB.4.0;data source=.. .."; } public abstract void Select(); public abstract void Process(); public virtual void Disconnect() { connectionString = ""; } public void Run() { Connect(); Select(); Process(); Disconnect(); } } |
ConcreteClass
1. 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() { DataTable dataTable = dataSet.Tables["Categories"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["CategoryName"]); } } } 2. 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() { DataTable dataTable = dataSet.Tables["Products"]; foreach (DataRow row in dataTable.Rows) { Console.WriteLine(row["ProductName"]); } Console.WriteLine(); } } |
static void Main() { DataAccessObject dao; dao = new Categories(); dao.Run(); dao = new Products(); dao.Run(); } |
Visitor
Defines a new operation to a class without change
Definition
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
Usage
Low
Participants
Visitor
interface IVisitor { void Visit(Element element); } |
ConcreteVisitor
1. class IncomeVisitor : IVisitor { public void Visit(Element element) { Employee employee = element as Employee; employee.Income *= 1.10; Console.WriteLine("{0}{1}'s new income: {2:C}", employee.GetType().Name, employee.Name, employee.Income); } } 2. class VacationVisitor : IVisitor { public void Visit(Element element) { Employee employee = element as Employee; Console.WriteLine("{0}{1}'s new vacation days:{2}", employee.GetType().Name, employee.Name, employee.VacationDays); } } |
Element
abstract class Element { public abstract void Accept(IVisitor visitor); } |
ConcreteElement
class Employee : Element { string name; double income; int vacationDays; public Employee(string name, double income, int vacationDays) { this.name = name; this.income = income; this.vacationDays = vacationDays; } public string Name { get{ return name; } set{ name = value; } } public double Income { get{ return income; } set{ income = value; } } public int VacationDays { get{ return vacationDays; } set{ vacationDays = value; } } public override void Accept(IVisitor visitor) { visitor.Visit(this); } } |
class Clerk : Employee { public Clerk() : base("Hank", 25000.0, 14) { } } class Director : Employee { public Director() : base("Elly", 35000.0, 16) { } } |
ObjectStructure
class Employees { private ArrayList employees = new ArrayList(); public void Attach(Employee employee) { employees.Add(employee); } public void Detach(Employee employee) { employees.Remove(employee); } public void Accept(IVisitor visitor) { foreach (Employee e in employees) { e.Accept(visitor); } Console.WriteLine(); } } |
static void Main() { // Setup employee collection Employees e = new Employees(); e.Attach(new Clerk()); e.Attach(new Director()); e.Accept(new IncomeVisitor()); e.Accept(new VacationVisitor()); } |
No comments:
Post a Comment