OOP vs !OOP

Advantages of OOP
1. Well-designed oop code EASY TO REUSE. Shared modules can be distributed as libraries which can be used in other applications.
2. INCAPSULATION. In well-designed OOP code in order to use OOP objects clients dont’t need to know how objects works internally they work with declared interfaces/contracts only.
3. MAINTAINABILITY. Well-designed code is easy to maintain it is easy to substitute one module with another without breaking functionality.
4. EASY TO WRITE LARGE APPLICATIONS.

Disadvantages of OOP
1. Performance. OOP have to deal with lots of objects in memory
2. LONG LEARNING CURVE.

Decorator pattern

Decorator

Decorator design pattern allows to attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Decorator
Decorator

Client

[TestMethod]
public void DecoratorTest()
{
    IComponent concreteComponent = new ConcreteComponent1();
    IComponent concreteDecorator1 = new ComponentDecorator1(concreteComponent);
    IComponent concreteDecorator2 = new ComponentDecorator2(concreteDecorator1);

    Assert.AreEqual(concreteDecorator1.Operation(), "ComponentDecorator1 + " + concreteComponent.Operation());
    Assert.AreEqual(concreteDecorator2.Operation(), "ComponentDecorator2 + " + ((ComponentDecorator2)concreteDecorator2).ExtendedOperation() + " + ComponentDecorator1 + " + concreteComponent.Operation());
}

The Component defines the interface for components that can have dynamically attached responsibilities.

/// <summary>
/// Declares the interface for components that can have dynamically attached responsibilities. 
/// </summary>
public interface IComponent
{
    string Operation();
}

The ConcreteComponent implements the Component’s interface to which responsibilities can be attached dynamically.

/// <summary>
/// Implements the Component's interface to which responsibilities can be attached dynamically.
/// </summary>
public class ConcreteComponent1 : IComponent
{

    public string Operation()
    {
        return "ConcreteComponent1";
    }
}

The Decorator maintains a reference to the Component’s object and defines the interface that conforms the Component’s interface

/// <summary>
/// Maintance a reference to the Component's object and define an interface that conforms the component's interface 
/// </summary>
public abstract class AbstractComponentDecorator : IComponent
{

    private IComponent _refToConcreteComponent;

	protected AbstractComponentDecorator(IComponent concreteComponent)
    {
        _refToConcreteComponent = concreteComponent;
    }


    public virtual string Operation()
    {
        return _refToConcreteComponent.Operation();
    }
}

The ComponentDecorator adds responsibilities to an attached component.

/// <summary>
/// Adds responsibilites to a component 
/// </summary>
public class ComponentDecorator1 : AbstractComponentDecorator
{
    public ComponentDecorator1(IComponent concreteComponent) : base(concreteComponent) { }

    public override string Operation()
    {
        return "ComponentDecorator1 + " + base.Operation();
    }
}

Command design pattern

Command design pattern
Command design pattern
Command design pattern

Command design pattern encapsulates request as an object thereby allowing parameterize other objects with different request, log and queue requests, and support undoable operations.

Command Real World Example
Command Real World Example

Test client:

[TestFixture]
public class CommandPatternTest
{
    private Calculator _calculator;
    private Invoker<int> _invoker;

    [SetUp]
    public void SetUp()
    {
        //Arrange
        _calculator = new Calculator();
        _invoker = new Invoker<int>();
    }

    [TestCase(1, 2, 3)]
    public void InvokedAddCommand_OnValidParams_ReturnsExpectedResult(int a, int b, int expectedResult)
    {
        //Arrange
        var addCommand = new AddCommand<int>(_calculator, a, b);
        //Act
        var actualResult = _invoker.SetAndExecuteCommand(addCommand);
        //Assert
        Assert.AreEqual(expectedResult, actualResult);
    }

    [TestCase(3, 2, 1)]
    public void InvokedSubtractCommand_OnValidParams_ReturnsExpectedResult(int a, int b, int expectedResult)
    {
        //Arrange
        var subtractCommand = new SubtractCommand<int>(_calculator, a, b);
        //Act
        var actualResult = _invoker.SetAndExecuteCommand(subtractCommand);
        Assert.AreEqual(expectedResult, actualResult);
    }

    [TestCase(1, 2, 3)]
    public void InvokedUndo_ReturnsExpectedResult(int a, int b, int expectedResult)
    {
        //Arrange
        var addCommand = new AddCommand<int>(_calculator, 1, 2);
        _invoker.SetAndExecuteCommand(addCommand);
        _invoker.SetAndExecuteCommand(addCommand);
        //Act
        var actualResult = _invoker.Undo();
        //Assert
        Assert.AreEqual(expectedResult, actualResult);
    }
}

Invoker:

/// 
/// The Invoker holds a command and calls command's execute method
/// 
/// 
public class Invoker where  T : struct, IConvertible, IComparable
{
    private Stack<ICalculatorCommand> _commands = new Stack<ICalculatorCommand>();        

    public void SetCommand(ICalculatorCommand command)
    {
        _commands.Push(command);            
    }

    public T SetAndExecuteCommand(ICalculatorCommand command)
    {
        _commands.Push(command);
        return command.Calculate();
    }        

    public T Execute()
    {
        return _commands.Peek().Calculate();
    }

    public T Undo()
    {
        if (!_commands.Any())
            throw new InvalidOperationException();
            
        _commands.Pop();
        return _commands.Peek().Calculate();           
    }
}

Receiver:

public enum Operand
{
    Add = '+',
    Subtract = '-'
}

/// 
/// A commands receiver, performs real actions 
/// 
public class Calculator
{
    public dynamic PerformCalculation(Operand operand, dynamic arg1, dynamic arg2)
    {
        switch (operand)
        {
            case Operand.Add:                    
                return arg1 + arg2;
            case Operand.Subtract:
                return arg1 - arg2;
        }
        return null;
    }
}

Abstract command:

public interface ICalculatorCommand where T : struct, IConvertible, IComparable
{
    T Calculate();
}

Concrete commands

public class AddCommand : ICalculatorCommand where T : struct, IConvertible, IComparable
{
    private Calculator _calculator;
    private T _arg1, _arg2;

    public AddCommand(Calculator calculator, T arg1, T arg2)
    {
        _calculator = calculator;
        _arg1 = arg1;
        _arg2 = arg2;
    }

    public T Calculate()
    {
        return (T)_calculator.PerformCalculation(Operand.Add, _arg1, _arg2);
    }
}

public class SubtractCommand : ICalculatorCommand where T : struct, IConvertible, IComparable
{
    private Calculator _calculator;
    private T _arg1, _arg2;

    public SubtractCommand(Calculator calculator, T arg1, T arg2)
    {
        _calculator = calculator;
        _arg1 = arg1;
        _arg2 = arg2;
    }

    public T Calculate()
    {
        return (T)_calculator.PerformCalculation(Operand.Subtract, _arg1, _arg2);
    }
}

State pattern

The state pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class.

Featured image

Real-world example

StateExample

Client

static void Main(string[] args)
{
	var guessingMachine = new GuessingMachine(10);
	Console.WriteLine(guessingMachine.Message);
	guessingMachine.Start();

	while (!(guessingMachine.State is TerminateState))
	{				
		Console.WriteLine(guessingMachine.Message);
		guessingMachine.Play(Console.ReadLine());

	}
}

 

Context class

public class GuessingMachine	
{

	public GuessingMachine(int maxAttemptsNumber)
	{
		MaxAttemptsNumber = maxAttemptsNumber;
		State = new NewGameState(this);
	}


	public int MaxAttemptsNumber { private set; get; }

	public IState State { set; get; }

	internal string UserAnswer { set; get; }

	public string Message 
	{
		get { return State.Message; }
	}

	public void Play(string answer)
	{
		this.UserAnswer = answer;
		State.Handle(this);
	}

	public void Start()
	{
		State.Start(this);
	}

	public void Stop()
	{
		State.Stop(this);
	}
}

 

State interface

public interface IState
{
	string Message { set; get; }

	void Start(GuessingMachine context);

	void Stop(GuessingMachine context);

	void Handle(GuessingMachine context);
}

 

New game state class

public class NewGameState : IState
{
	public string Message { set; get; }

	public NewGameState(GuessingMachine context)
	{
		Message = String.Format("Pick a number between 1 and 10. You will have {0} turns. Good luck!", context.MaxAttemptsNumber);	
	}

	public void Handle(GuessingMachine context)
	{
		Message = String.Format("You should start a new game!");	
	}


	public void Start(GuessingMachine context)
	{
		var rand = new Random((int)DateTime.Now.Ticks & 0x0000FFFF);
		context.State = new GuessingState(context, rand.Next(1, 10));
	}

	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Guessing state class

public class GuessingState : IState
{
	public int Attempt { set; get; }
	public string Message { set; get; }

	private int NumberToGuess { set; get; }

	public GuessingState(GuessingMachine context, int numberToGuess)
	{
		Attempt = 1;
		NumberToGuess = numberToGuess;
		Message = String.Format("You have {0} attempts left", context.MaxAttemptsNumber);
	}

	public void Handle(GuessingMachine context)
	{
		int answer = int.Parse(context.UserAnswer);

		if (answer == NumberToGuess)
			context.State = new WinnerState();
		else if (Attempt >= context.MaxAttemptsNumber)
			context.State = new LoserState();
		else
		{
			Message = String.Format("You have {0} attempts left", context.MaxAttemptsNumber - Attempt);
			Attempt++;
		}
	}


	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Winner state class

class WinnerState : IState
{
	public string Message { set; get; }

	public WinnerState()
	{
		Message = "Good guess! You have won the game! Do you want to play a new game? (Y / N)";			
	}

	public void Handle(GuessingMachine context)
	{
		if (context.UserAnswer.ToUpperInvariant() == "Y")
			Start(context);
		else if (context.UserAnswer.ToUpperInvariant() == "N")
			Stop(context);
		Message = "Do you want to play a new game? (Y / N)";			
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}


	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Loser state class

public class LoserState : IState
{
	public string Message { set; get; }

	public LoserState()
	{
		Message = "You have lost the game!  Do you want to play a new game? (Y / N)";
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Handle(GuessingMachine context)
	{
		if (context.UserAnswer.ToUpperInvariant() == "Y")
			Start(context);
		else if (context.UserAnswer.ToUpperInvariant() == "N")
			Stop(context);
		Message = "Do you want to play a new game? (Y / N)";			
	}


	public void Stop(GuessingMachine context)
	{
		context.State = new TerminateState(context);
	}
}

 

Terminate state class

public class TerminateState : IState
{
	public string Message
	{
		set;
		get;
	}

	public TerminateState(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}

	public void Start(GuessingMachine context)
	{
		context.State = new NewGameState(context);
		context.Start();
	}

	public void Stop(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}

	public void Handle(GuessingMachine context)
	{
		Message = "The game has been stopped!";
	}
}

Structural.Decorator design pattrn

Allows to add responsibilities dynamically without subclassing


/*
* Attaches additional responisbilities for an object dynamically.
* Allows to add additional behavior without subclassing
*/
namespace Structural.Decorator
{
///

/// Declares an interface for components.
///

public interface IComponent
{
string Operation();
}

///

/// Implements component interface
///

public class ConcreteComponent1 : IComponent
{

public string Operation()
{
return "ConcreteComponent1";
}
}

///

/// Implements component interface
///

public class ConcreteComponent2 : IComponent
{

public string Operation()
{
return "ConcreteComponent2";
}
}

///

/// Maintains a reference to a component. Implements a basic operations of a component
///

public abstract class AbstractComponentDecorator : IComponent
{

private IComponent _refToConcreteComponent;

public AbstractComponentDecorator(IComponent concreteComponent)
{
_refToConcreteComponent = concreteComponent;
}

public virtual string Operation()
{
return _refToConcreteComponent.Operation();
}
}

///

/// Extends functionality of a component, provides a reference to a component
///

public class ComponentDecorator1 : AbstractComponentDecorator
{
public ComponentDecorator1(IComponent concreteComponent) : base(concreteComponent) { }

public override string Operation()
{
return "ComponentDecorator1 + " + base.Operation();
}
}

///

/// Extends functionality of a component, provides a reference to a component
///

public class ComponentDecorator2 : AbstractComponentDecorator
{
public ComponentDecorator2(IComponent concreteComponent) : base(concreteComponent) { }

public override string Operation()
{
return "ComponentDecorator2 + " + ExtendedOperation() + " + " + base.Operation();
}

public string ExtendedOperation()
{
return "ExtendedOperation";
}
}

}