Design Patterns
https://www.dofactory.com/net/design-patterns
Creational Patterns
Singleton Pattern
Strategy pattern
https://en.wikipedia.org/wiki/Strategy_pattern
The strategy pattern(also known as thepolicy pattern) is a behavioral software design patternthat enables selecting analgorithmat runtime. Deferring the decision about which algorithm to use until runtime allows the calling code to be more flexible and reusable.
According to the strategy pattern, the behaviors of a class should not be inherited. Instead they should be encapsulated using interfaces. This is compatible with the open/closed principle (OCP), which proposes that classes should be open for extension but closed for modification.
As an example, consider a car class. Two possible functionalities for car are brake and accelerate. Since accelerate and brake behaviors change frequently between models, a common approach is to implement these behaviors in subclasses. This approach has significant drawbacks: accelerate and brake behaviors must be declared in each new Car model. The work of managing these behaviors increases greatly as the number of models increases, and requires code to be duplicated across models. Additionally, it is not easy to determine the exact nature of the behavior for each model without investigating the code in each.
The strategy pattern uses composition instead of inheritance. In the strategy pattern, behaviors are defined as separate interfaces and specific classes that implement these interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time.
public class StrategyPatternWiki
{
public static void Main(String[] args)
{
// Prepare strategies
IBillingStrategy normalStrategy = new NormalStrategy();
IBillingStrategy happyHourStrategy = new HappyHourStrategy();
Customer firstCustomer = new Customer(normalStrategy);
// Normal billing
firstCustomer.Add(1.0, 1);
// Start Happy Hour
firstCustomer.Strategy = happyHourStrategy;
firstCustomer.Add(1.0, 2);
// New Customer
Customer secondCustomer = new Customer(happyHourStrategy);
secondCustomer.Add(0.8, 1);
// The Customer pays
firstCustomer.PrintBill();
// End Happy Hour
secondCustomer.Strategy = normalStrategy;
secondCustomer.Add(1.3, 2);
secondCustomer.Add(2.5, 1);
secondCustomer.PrintBill();
}
}
class Customer
{
private IList<double> drinks;
// Get/Set Strategy
public IBillingStrategy Strategy { get; set; }
public Customer(IBillingStrategy strategy)
{
this.drinks = new List<double>();
this.Strategy = strategy;
}
public void Add(double price, int quantity)
{
drinks.Add(Strategy.GetActPrice(price * quantity));
}
// Payment of bill
public void PrintBill()
{
double sum = 0;
foreach (double i in drinks)
{
sum += i;
}
Console.WriteLine("Total due: " + sum);
drinks.Clear();
}
}
interface IBillingStrategy
{
double GetActPrice(double rawPrice);
}
// Normal billing strategy (unchanged price)
class NormalStrategy : IBillingStrategy
{
public double GetActPrice(double rawPrice)
{
return rawPrice;
}
}
// Strategy for Happy hour (50% discount)
class HappyHourStrategy : IBillingStrategy
{
public double GetActPrice(double rawPrice)
{
return rawPrice * 0.5;
}
}
State pattern
https://en.wikipedia.org/wiki/State_pattern
https://www.dofactory.com/net/state-design-pattern
The state pattern is a behavioral software design pattern that implements a state machine in an object-oriented way. With the state pattern, a state machine is implemented by implementing each individual state as a derived class of the state pattern interface, and implementing state transitions by invoking methods defined by the pattern's superclass.
using System;
namespace DoFactory.GangOfFour.State.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// State Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Setup context in a state
Context c = new Context(new ConcreteStateA());
// Issue requests, which toggles state
c.Request();
c.Request();
c.Request();
c.Request();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'State' abstract class
/// </summary>
abstract class State
{
public abstract void Handle(Context context);
}
/// <summary>
/// A 'ConcreteState' class
/// </summary>
class ConcreteStateA : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateB();
}
}
/// <summary>
/// A 'ConcreteState' class
/// </summary>
class ConcreteStateB : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateA();
}
}
/// <summary>
/// The 'Context' class
/// </summary>
class Context
{
private State _state;
// Constructor
public Context(State state)
{
this.State = state;
}
// Gets or sets the state
public State State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State: " +
_state.GetType().Name);
}
}
public void Request()
{
_state.Handle(this);
}
}
}
Special Case Pattern
https://martinfowler.com/eaaCatalog/specialCase.html
Null object Pattern
https://en.wikipedia.org/wiki/Null_object_pattern
/* Null object pattern implementation:
*/
using System;
// Animal interface is the key to compatibility for Animal implementations below.
interface IAnimal
{
void MakeSound();
}
// Animal is the base case.
abstract class Animal : IAnimal
{
// A shared instance that can be used for comparisons
public static readonly IAnimal Null = new NullAnimal();
// The Null Case: this NullAnimal class should be used in place of C# null keyword.
private class NullAnimal : Animal
{
public override void MakeSound()
{
// Purposefully provides no behaviour.
}
}
public abstract void MakeSound();
}
// Dog is a real animal.
class Dog : IAnimal
{
public void MakeSound()
{
Console.WriteLine("Woof!");
}
}
/* =========================
* Simplistic usage example in a Main entry point.
*/
static class Program
{
static void Main()
{
IAnimal dog = new Dog();
dog.MakeSound(); // outputs "Woof!"
/* Instead of using C# null, use the Animal.Null instance.
* This example is simplistic but conveys the idea that if the Animal.Null instance is used then the program
* will never experience a .NET System.NullReferenceException at runtime, unlike if C# null were used.
*/
IAnimal unknown = Animal.Null; //<< replaces: IAnimal unknown = null;
unknown.MakeSound(); // outputs nothing, but does not throw a runtime exception
}
}