1. Strategy
Pattern
The strategy pattern is a behavioral design pattern that enables selecting an algorithm at runtime
The key idea is to create objects which represent various strategies. These objects form a pool of strategies from which the context object can choose from to vary its behavior as per its strategy.
Sorting algorithms have a set of rule specific to each other they follow to effectively sort an array of numbers. We have the
· Bubble Sort
· Linear Search
· Heap Sort
· Merge Sort
· Selection Sort
Strategy
Pattern supports the SOLID principles and forces us to abide by it. The D in
SOLID says we must depend on abstractions, not on concretions.
// In an OOP Language -
// TypeScript
// interface all sorting algorithms must implement
interface SortingStrategy {
sort(array);
}
// heap sort algorithm implementing the `SortingStrategy` interface, it implements its algorithm in the `sort` method
class HeapSort implements SortingStrategy {
sort() {
log("HeapSort algorithm")
// implementation here
}
}
// linear search sorting algorithm implementing the `SortingStrategy` interface, it implements its algorithm in the `sort` method
class LinearSearch implements SortingStrategy {
sort(array) {
log("LinearSearch algorithm")
// implementation here
}
}
class SortingProgram {
private sortingStrategy: SortingStrategy
constructor(array: Array<Number>) {
}
runSort(sortingStrategy: SortingStrategy) {
return this.sortingStrategy.sort(this.array)
}
}
// instantiate the `SortingProgram` with an array of numbers
const sortProgram = new SortingProgram([9,2,5,3,8,4,1,8,0,3])
// sort using heap sort
sortProgram.runSort(new HeapSort())
// sort using linear search
sortProgram.runSort(new LinearSearch())
2. Observer Design Pattern
Observer is a behavioral design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.
Problem:
Imagine that you have two types of objects: a Customer and a Store. The customer is very interested in a particular brand of product (say, it’s a new model of the iPhone) which should become available in the store very soon.
The customer could visit the store every day and check product availability. But while the product is still en route, most of these trips would be pointless.
On the other hand, the store could send tons of emails (which might be considered spam) to all customers each time a new product becomes available. This would save some customers from endless trips to the store. At the same time, it’d upset other customers who aren’t interested in new products.
It looks like we’ve got a conflict. Either the customer wastes time checking product availability or the store wastes resources notifying the wrong customers.
namespace Observer
{
public class Program
{
public static void Main()
{
var per = new Person("Subash");
Console.WriteLine(per.PersonName);
var profile = new ProfileUpdate(per);
profile.SubscribeEvent();
profile.ChangeName("Selvan");
Console.WriteLine(per.PersonName);
profile.UnSubscribeEvent();
}
}
public class NotifyPropertyChanged : INotifyPropertyChanged
{
private bool _eventsSourceEnabled;
private List<string> _propertyNamesCollection = new List<string>();
public event PropertyChangedEventHandler PropertyChanged;
public void StartEventSourcing()
{
_eventsSourceEnabled = true;
}
public void StopEventSourcing(bool distinctEvents = true)
{
_eventsSourceEnabled = false;
var currentBuffer = _propertyNamesCollection.ToList();
_propertyNamesCollection.Clear();
if (distinctEvents)
{
currentBuffer = currentBuffer.Distinct().ToList();
}
foreach (var propertyName in currentBuffer)
{
RaiseEvent(propertyName);
}
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
if (_eventsSourceEnabled)
{
_propertyNamesCollection.Add(propertyName);
}
else
{
RaiseEvent(propertyName);
}
}
private void RaiseEvent(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Person : NotifyPropertyChanged
{
private string name;
public Person(string Name)
{
name = Name;
}
public string PersonName
{
get { return name; }
set
{
name = value;
// Call OnPropertyChanged whenever the property is updated
RaisePropertyChanged();
}
}
}
public class ProfileUpdate
{
private Person perObj = null;
public ProfileUpdate(Person obj)
{
perObj = obj;
}
public void SubscribeEvent()
{
perObj.PropertyChanged += OnPropertyChangedEvent;
}
public void UnSubscribeEvent()
{
perObj.PropertyChanged -= OnPropertyChangedEvent;
}
public void ChangeName(string Name)
{
perObj.PersonName = Name;
}
private void OnPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("Name Changed Invoked");
}
}
}
// A simple Java program to demonstrate
// implementation of Command Pattern using
// a remote control example.
// An interface for command
interface Command
{
public void execute();
}
// Light class and its corresponding command
// classes
class Light
{
public void on()
{
System.out.println("Light is on");
}
public void off()
{
System.out.println("Light is off");
}
}
class LightOnCommand implements Command
{
Light light;
// The constructor is passed the light it
// is going to control.
public LightOnCommand(Light light)
{
this.light = light;
}
public void execute()
{
light.on();
}
}
class LightOffCommand implements Command
{
Light light;
public LightOffCommand(Light light)
{
this.light = light;
}
public void execute()
{
light.off();
}
}
// Stereo and its command classes
class Stereo
{
public void on()
{
System.out.println("Stereo is on");
}
public void off()
{
System.out.println("Stereo is off");
}
public void setCD()
{
System.out.println("Stereo is set " +
"for CD input");
}
public void setDVD()
{
System.out.println("Stereo is set"+
" for DVD input");
}
public void setRadio()
{
System.out.println("Stereo is set" +
" for Radio");
}
public void setVolume(int volume)
{
// code to set the volume
System.out.println("Stereo volume set"
+ " to " + volume);
}
}
class StereoOnWithCDCommand implements Command
{
Stereo stereo;
public StereoOnWithCDCommand(Stereo stereo)
{
this.stereo = stereo;
}
public void execute()
{
stereo.on();
stereo.setCD();
stereo.setVolume(11);
}
}
// A Simple remote control with one button
class SimpleRemoteControl
{
Command slot; // only one button
public SimpleRemoteControl()
{
}
public void setCommand(Command command)
{
// set the command the remote will
// execute
slot = command;
}
public void buttonWasPressed()
{
slot.execute();
}
}
// Driver class
class RemoteControlTest
{
public static void main(String[] args)
{
SimpleRemoteControl remote =
new SimpleRemoteControl();
Light light = new Light();
Stereo stereo = new Stereo();
// we can change command dynamically
remote.setCommand(new
LightOnCommand(light));
remote.buttonWasPressed();
remote.setCommand(new
StereoOnWithCDCommand(stereo));
remote.buttonWasPressed();
}
}
- Makes our code extensible as we can add new commands without changing existing code.
- Reduces coupling between the invoker and receiver of a command.
- Increase in the number of classes for each individual command
using System;
using System.Collections.Generic;
namespace Mediator.RealWorld
{
/// <summary>
/// The 'Mediator' abstract class
/// </summary>
public abstract class AbstractChatroom
{
public abstract void Register(Participant participant);
public abstract void Send(
string from, string to, string message);
}
/// <summary>
/// The 'ConcreteMediator' class
/// </summary>
public class Chatroom : AbstractChatroom
{
private Dictionary<string, Participant> participants = new Dictionary<string, Participant>();
public override void Register(Participant participant)
{
if (!participants.ContainsValue(participant))
{
participants[participant.Name] = participant;
}
participant.Chatroom = this;
}
public override void Send(string from, string to, string message)
{
Participant participant = participants[to];
if (participant != null)
{
participant.Receive(from, message);
}
}
}
/// <summary>
/// The 'AbstractColleague' class
/// </summary>
public class Participant
{
Chatroom chatroom;
string name;
// Constructor
public Participant(string name)
{
this.name = name;
}
// Gets participant name
public string Name
{
get { return name; }
}
// Gets chatroom
public Chatroom Chatroom
{
set { chatroom = value; }
get { return chatroom; }
}
// Sends message to given participant
public void Send(string to, string message)
{
chatroom.Send(name, to, message);
}
// Receives message from given participant
public virtual void Receive(
string from, string message)
{
Console.WriteLine("{0} to {1}: '{2}'",
from, Name, message);
}
}
/// <summary>
/// A 'ConcreteColleague' class
/// </summary>
public class Beatle : Participant
{
// Constructor
public Beatle(string name)
: base(name)
{
}
public override void Receive(string from, string message)
{
Console.Write("To a Beatle: ");
base.Receive(from, message);
}
}
/// <summary>
/// A 'ConcreteColleague' class
/// </summary>
public class NonBeatle : Participant
{
// Constructor
public NonBeatle(string name)
: base(name)
{
}
public override void Receive(string from, string message)
{
Console.Write("To a non-Beatle: ");
base.Receive(from, message);
}
}
/// <summary>
/// Mediator Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create chatroom
Chatroom chatroom = new Chatroom();
// Create participants and register them
Participant George = new Beatle("George");
Participant Paul = new Beatle("Paul");
Participant Ringo = new Beatle("Ringo");
Participant John = new Beatle("John");
Participant Yoko = new NonBeatle("Yoko");
chatroom.Register(George);
chatroom.Register(Paul);
chatroom.Register(Ringo);
chatroom.Register(John);
chatroom.Register(Yoko);
// Chatting participants
Yoko.Send("John", "Hi John!");
Paul.Send("Ringo", "All you need is love");
Ringo.Send("George", "My sweet Lord");
Paul.Send("John", "Can't buy me love");
John.Send("Yoko", "My sweet love");
// Wait for user
Console.ReadKey();
}
}
}
To a Beatle: Yoko to John: 'Hi John!'
To a Beatle: Paul to Ringo: 'All you need is love'
To a Beatle: Ringo to George: 'My sweet Lord'
To a Beatle: Paul to John: 'Can't buy me love'
To a non-Beatle: John to Yoko: 'My sweet love'
Memento is a behavioral design pattern that lets you save and restore the previous state of an object without revealing the details of its implementation.
using System;
namespace Memento.RealWorld
{
/// <summary>
/// The 'Originator' class
/// </summary>
public class SalesProspect
{
string name;
string phone;
double budget;
// Gets or sets name
public string Name
{
get { return name; }
set
{
name = value;
Console.WriteLine("Name: " + name);
}
}
// Gets or sets phone
public string Phone
{
get { return phone; }
set
{
phone = value;
Console.WriteLine("Phone: " + phone);
}
}
// Gets or sets budget
public double Budget
{
get { return budget; }
set
{
budget = value;
Console.WriteLine("Budget: " + budget);
}
}
// Stores memento
public Memento SaveMemento()
{
Console.WriteLine("\nSaving state --\n");
return new Memento(name, phone, budget);
}
// Restores memento
public void RestoreMemento(Memento memento)
{
Console.WriteLine("\nRestoring state --\n");
Name = memento.Name;
Phone = memento.Phone;
Budget = memento.Budget;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
public class Memento
{
string name;
string phone;
double budget;
// Constructor
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; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
public class ProspectMemory
{
Memento memento;
public Memento Memento
{
set { memento = value; }
get { return memento; }
}
}
/// <summary>
/// Memento Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
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);
// Wait for user
Console.ReadKey();
}
}
}
Name: Noel van Halen
Phone: (412) 256-0990
Budget: 25000
Saving state --
Name: Leo Welch
Phone: (310) 209-7111
Budget: 1000000
Restoring state --
Name: Noel van Halen
Phone: (412) 256-0990
Budget: 25000
- When the phone is unlocked, pressing buttons leads to executing various functions.
- When the phone is locked, pressing any button leads to the unlock screen.
- When the phone’s charge is low, pressing any button shows the charging screen.
using System;
namespace State.RealWorld
{
/// <summary>
/// The 'State' abstract class
/// </summary>
public abstract class State
{
protected Account account;
protected double balance;
protected double interest;
protected double lowerLimit;
protected double upperLimit;
// Properties
public Account Account
{
get { return account; }
set { account = value; }
}
public double Balance
{
get { return balance; }
set { balance = value; }
}
public abstract void Deposit(double amount);
public abstract void Withdraw(double amount);
public abstract void PayInterest();
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Red indicates that account is overdrawn
/// </remarks>
/// </summary>
public class RedState : State
{
private double serviceFee;
// Constructor
public RedState(State state)
{
this.balance = state.Balance;
this.account = state.Account;
Initialize();
}
private void Initialize()
{
// Should come from a datasource
interest = 0.0;
lowerLimit = -100.0;
upperLimit = 0.0;
serviceFee = 15.00;
}
public override void Deposit(double amount)
{
balance += amount;
StateChangeCheck();
}
public override void Withdraw(double amount)
{
amount = amount - serviceFee;
Console.WriteLine("No funds available for withdrawal!");
}
public override void PayInterest()
{
// No interest is paid
}
private void StateChangeCheck()
{
if (balance > upperLimit)
{
account.State = new SilverState(this);
}
}
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Silver indicates a non-interest bearing state
/// </remarks>
/// </summary>
public class SilverState : State
{
// Overloaded constructors
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()
{
// Should come from a datasource
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();
}
public override void PayInterest()
{
balance += interest * balance;
StateChangeCheck();
}
private void StateChangeCheck()
{
if (balance < lowerLimit)
{
account.State = new RedState(this);
}
else if (balance > upperLimit)
{
account.State = new GoldState(this);
}
}
}
/// <summary>
/// A 'ConcreteState' class
/// <remarks>
/// Gold indicates an interest bearing state
/// </remarks>
/// </summary>
public 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()
{
// Should come from a database
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();
}
public override void PayInterest()
{
balance += interest * balance;
StateChangeCheck();
}
private void StateChangeCheck()
{
if (balance < 0.0)
{
account.State = new RedState(this);
}
else if (balance < lowerLimit)
{
account.State = new SilverState(this);
}
}
}
/// <summary>
/// The 'Context' class
/// </summary>
public class Account
{
private State state;
private string owner;
// Constructor
public Account(string owner)
{
// New accounts are 'Silver' by default
this.owner = owner;
this.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("Deposited {0:C} --- ", amount);
Console.WriteLine(" Balance = {0:C}", this.Balance);
Console.WriteLine(" Status = {0}",
this.State.GetType().Name);
Console.WriteLine("");
}
public void Withdraw(double amount)
{
state.Withdraw(amount);
Console.WriteLine("Withdrew {0:C} --- ", amount);
Console.WriteLine(" Balance = {0:C}", this.Balance);
Console.WriteLine(" Status = {0}\n",
this.State.GetType().Name);
}
public void PayInterest()
{
state.PayInterest();
Console.WriteLine("Interest Paid --- ");
Console.WriteLine(" Balance = {0:C}", this.Balance);
Console.WriteLine(" Status = {0}\n",
this.State.GetType().Name);
}
}
/// <summary>
/// State Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Open a new account
Account account = new Account("Jim Johnson");
// Apply financial transactions
account.Deposit(500.0);
account.Deposit(300.0);
account.Deposit(550.0);
account.PayInterest();
account.Withdraw(2000.00);
account.Withdraw(1100.00);
// Wait for user
Console.ReadKey();
}
}
}
Deposited $500.00 ---
Balance = $500.00
Status = SilverState
Deposited $300.00 ---
Balance = $800.00
Status = SilverState
Deposited $550.00 ---
Balance = $1,350.00
Status = GoldState
Interest Paid ---
Balance = $1,417.50
Status = GoldState
Withdrew $2,000.00 ---
Balance = ($582.50)
Status = RedState
No funds available for withdrawal!
Withdrew $1,100.00 ---
Balance = ($582.50)
Status = RedState
- An object structure must have many unrelated operations to perform on it.
- An object structure cannot change but operations performed on it can change.
- The operations need to perform on the concrete classes of an object structure.
- Exposing the internal state or operations of the object structure is acceptable.
- Operations should be able to operate on multiple object structures that implement the same interface.
namespace VisitorDesignPattern
{
public interface IElement
{
void Accept(IVisitor visitor);
}
public class Kid : IElement
{
public string KidName { get; set; }
public Kid(string name)
{
KidName = name;
}
public void Accept(IVisitor visitor)
{
visitor.Visit(this);
}
}
}
namespace VisitorDesignPattern
{
public interface IVisitor
{
void Visit(IElement element);
}
public class Doctor : IVisitor
{
public string Name { get; set; }
public Doctor(string name)
{
Name = name;
}
public void Visit(IElement element)
{
Kid kid = (Kid)element;
Console.WriteLine("Doctor: " + this.Name+ " did the health checkup of the child: "+ kid.KidName);
}
}
class Salesman : IVisitor
{
public string Name { get; set; }
public Salesman(string name)
{
Name = name;
}
public void Visit(IElement element)
{
Kid kid = (Kid)element;
Console.WriteLine("Salesman: " + this.Name + " gave the school bag to the child: "
+ kid.KidName);
}
}
}
using System.Collections.Generic;
namespace VisitorDesignPattern
{
public class School
{
private static List<IElement> elements;
static School()
{
elements = new List<IElement>
{
new Kid("Ram"),
new Kid("Sara"),
new Kid("Pam")
};
}
public void PerformOperation(IVisitor visitor)
{
foreach (var kid in elements)
{
kid.Accept(visitor);
}
}
}
}
using System;
namespace VisitorDesignPattern
{
class Program
{
static void Main(string[] args)
{
School school = new School();
var visitor1 = new Doctor("James");
school.PerformOperation(visitor1);
Console.WriteLine();
var visitor2 = new Salesman("John");
school.PerformOperation(visitor2);
Console.Read();
}
}
}
Doctor: James did the health checkup of the child: Ram
Doctor: James did the health checkup of the child: Sara
Doctor: James did the health checkup of the child: Pam
Salesman: John gave the school bag to the child: Ram
Salesman: John gave the school bag to the child: Sara
Salesman: John gave the school bag to the child: Pam
using System;
namespace TemplateMethodDesignPattern
{
public abstract class HouseTemplate
{
// Template method defines the sequence for building a house
public void BuildHouse()
{
BuildFoundation();
BuildPillars();
BuildWalls();
BuildWindows();
Console.WriteLine("House is built");
}
// Methods to be implemented by subclasses
protected abstract void BuildFoundation();
protected abstract void BuildPillars();
protected abstract void BuildWalls();
protected abstract void BuildWindows();
}
}
using System;
namespace TemplateMethodDesignPattern
{
public class ConcreteHouse : HouseTemplate
{
protected override void BuildFoundation()
{
Console.WriteLine("Building foundation with cement, iron rods and sand");
}
protected override void BuildPillars()
{
Console.WriteLine("Building Concrete Pillars with Cement and Sand");
}
protected override void BuildWalls()
{
Console.WriteLine("Building Concrete Walls");
}
protected override void BuildWindows()
{
Console.WriteLine("Building Concrete Windows");
}
}
}
using System;
namespace TemplateMethodDesignPattern
{
public class WoodenHouse : HouseTemplate
{
protected override void BuildFoundation()
{
Console.WriteLine("Building foundation with cement, iron rods, wood and sand");
}
protected override void BuildPillars()
{
Console.WriteLine("Building wood Pillars with wood coating");
}
protected override void BuildWalls()
{
Console.WriteLine("Building Wood Walls");
}
protected override void BuildWindows()
{
Console.WriteLine("Building Wood Windows");
}
}
}
using System;
namespace TemplateMethodDesignPattern
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Build a Concrete House\n");
HouseTemplate houseTemplate = new ConcreteHouse();
// call the template method
houseTemplate.BuildHouse();
Console.WriteLine();
Console.WriteLine("Build a Wooden House\n");
houseTemplate = new WoodenHouse();
// call the template method
houseTemplate.BuildHouse();
Console.Read();
}
}
}
Build a Concrete House
Building foundation with cement, iron rods and sand
Building Concrete Pillars with Cement and Sand
Building Concrete Walls
Building Concrete Windows
House is built
Build a Wooden House
Building foundation with cement, iron rods, wood and sand
Building wood Pillars with wood coating
Building Wood Walls
Building Wood Windows
House is built
No comments:
Post a Comment