Design patterns in C# – part 23 (Memento pattern)

Role

This pattern is used to capture an object’s internal state and save it externally so that it can be restored later.

Design

MementoPattern

Implementation

  • Client -> TestMementoPattern
  • Originator -> ItemsManager
  • Memento -> Memento
  • Caretaker -> Storage
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace MementoPattern
{
    public class TestMementoPattern
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("APPLICATION START \n\n");

            var storage = new Storage();
            var manager = new ItemsManager();
            var itemsGenerator = new ItemsGenerator();

            Console.WriteLine("######################################");

            manager.Operation(itemsGenerator[1]);
            manager.Operation(itemsGenerator[0]);
            manager.Operation(itemsGenerator[3]);
            manager.Operation(itemsGenerator[2]);

            Console.WriteLine("######################################");

            storage.Memento = manager.Save();
            manager.DisplayOperations();

            Console.WriteLine("######################################");

            manager.Operation(itemsGenerator[0]);
            manager.Operation(itemsGenerator[0]);
            manager.Operation(itemsGenerator[1]);

            Console.WriteLine("######################################");

            manager.DisplayOperations();

            manager.Restore(storage.Memento);
            manager.DisplayOperations();

            Console.WriteLine("######################################");

            manager.Operation(itemsGenerator[4]);
            manager.Operation(itemsGenerator[5]);

            Console.WriteLine("######################################");

            manager.DisplayOperations();
        }
    }

    public class Storage
    {
        public Memento Memento { get; set; }
    }

    public class ItemsGenerator
    {
        private readonly Item[] _items = {
                                             new Item("First", 1),
                                             new Item("Second", 2),
                                             new Item("Third", 3),
                                             new Item("Fourth", 4),
                                             new Item("Fifth", 5),
                                             new Item("Sixth", 6),
                                         };

        public Item this[int index]
        {
            get { return this._items[index]; }
        }
    }

    [Serializable]
    public class ItemsManager
    {
        private List<Item> _items;

        public ItemsManager()
        {
            this._items = new List<Item>();
        }

        public void Operation(Item item)
        {
            this._items.Add(item);
            Console.WriteLine("\t\tOperations {0} is executed", item);
        }

        public Memento Save()
        {
            Console.WriteLine("\n\nSAVE\n");

            var memento = new Memento();
            return memento.Save(this._items);
        }

        public void Restore(Memento memento)
        {
            Console.WriteLine("\n\nRESTORE\n");
            this._items = (List<Item>) memento.Restore();
        }

        public void DisplayOperations()
        {
            Console.WriteLine("======================================");
            Console.WriteLine("MANAGER - actual executed operations:\n");

            foreach (Item item in this._items)
            {
                Console.WriteLine(item);
            }

            Console.WriteLine("======================================");
        }
    }

    [Serializable]
    public class Memento
    {
        private readonly BinaryFormatter _binaryFormatter;
        private readonly MemoryStream _memoryStream;

        public Memento()
        {
            this._memoryStream = new MemoryStream();
            this._binaryFormatter = new BinaryFormatter();
        }

        public Memento Save(object obj)
        {
            this._binaryFormatter.Serialize(this._memoryStream, obj);
            return this;
        }

        public object Restore()
        {
            this._memoryStream.Seek(0, SeekOrigin.Begin);
            object obj = this._binaryFormatter.Deserialize(this._memoryStream);
            this._memoryStream.Close();
            return obj;
        }
    }

    [Serializable]
    public class Item
    {
        public Item(string name, int value)
        {
            this.Value = value;
            this.Name = name;
        }

        public int Value { get; private set; }
        public string Name { get; private set; }

        public override string ToString()
        {
            return String.Format("\t[Name = \"{0}\", \tValue = {1}]", this.Name, this.Value);
        }
    }
}

OUTPUT:

APPLICATION START

######################################
Operations      [Name = "Second",       Value = 2] is executed
Operations      [Name = "First",        Value = 1] is executed
Operations      [Name = "Fourth",       Value = 4] is executed
Operations      [Name = "Third",        Value = 3] is executed
######################################

SAVE

======================================
MANAGER – actual executed operations:

[Name = "Second",       Value = 2]
[Name = "First",        Value = 1]
[Name = "Fourth",       Value = 4]
[Name = "Third",        Value = 3]
======================================
######################################
Operations      [Name = "First",        Value = 1] is executed
Operations      [Name = "First",        Value = 1] is executed
Operations      [Name = "Second",       Value = 2] is executed
######################################
======================================
MANAGER – actual executed operations:

[Name = "Second",       Value = 2]
[Name = "First",        Value = 1]
[Name = "Fourth",       Value = 4]
[Name = "Third",        Value = 3]
[Name = "First",        Value = 1]
[Name = "First",        Value = 1]
[Name = "Second",       Value = 2]
======================================

RESTORE

======================================
MANAGER – actual executed operations:

[Name = "Second",       Value = 2]
[Name = "First",        Value = 1]
[Name = "Fourth",       Value = 4]
[Name = "Third",        Value = 3]
======================================
######################################
Operations      [Name = "Fifth",        Value = 5] is executed
Operations      [Name = "Sixth",        Value = 6] is executed
######################################
======================================
MANAGER – actual executed operations:

[Name = "Second",       Value = 2]
[Name = "First",        Value = 1]
[Name = "Fourth",       Value = 4]
[Name = "Third",        Value = 3]
[Name = "Fifth",        Value = 5]
[Name = "Sixth",        Value = 6]
======================================

Use when

  • An object’s state must be saved to be restored later, and
  • It is undesirable to expose the state directly.

Bibliography

Design patterns in C# – part 22 (Interpreter pattern)

Role

The Interpreter pattern supports the interpretation of instructions written in a language or notation defined for a specific purpose. The notatation is precise and can be defined in terms of a grammar.

Design

InterpreterPattern

Implementation

OUTPUT:

Use when

You have a grammar to be interpreted and:

  • The grammar is not too large.
  • Efficiency is not critical.
  • Parsing tools are available.
  • XML is an option for the specification.

Bibliography

Design patterns in C# – part 21 (Visitor pattern)

Role

The Visitor pattern defines and performs new operations on all the elements of an existing structure, without altering its classes.

Design

VisitorPattern

Implementation

  • Client -> TestVisitorPattern
  • Element -> Control
  • IVisitor -> Visitor
  • Visitor1 -> CountVisitor
using System;
using System.Collections.Generic;
using System.Reflection;

namespace VisitorPattern
{
    public class TestVisitorPattern
    {
        public static void Main(string[] args)
        {
            var root = new Control();

            var control1 = new Control();
            var control2 = new Control();
            var control3 = new Control();
            var control4 = new Control();
            var control5 = new Control();

            root.Controls.Add(control1);
            root.Controls.Add(control2);
            control2.Controls.Add(control3);
            control2.Controls.Add(control4);
            control2.Controls.Add(control5);

            Console.WriteLine("Count the elements");
            var visitor = new CountVisitor();
            visitor.CountElements(root);
            Console.WriteLine("Number of Elements is: {0}", visitor.Count);
        }
    }

    public abstract class Visitor
    {
        public void ReflectiveVisit(Control control)
        {
            var types = new[] {control.GetType()};
            MethodInfo methodInfo = GetType().GetMethod("Visit", types);

            if (methodInfo != null)
            {
                methodInfo.Invoke(this, new object[] {control});
            }
        }
    }

    public class CountVisitor : Visitor
    {
        public int Count { get; set; }

        public void CountElements(Control control)
        {
            ReflectiveVisit(control);

            if (control.Controls == null)
            {
                return;
            }

            foreach (Control c in control.Controls)
            {
                this.CountElements(c);
            }
        }

        public void Visit(Control control)
        {
            this.Count++;
        }
    }

    public class Control
    {
        public Control()
        {
            this.Controls = new List<Control>();
        }

        public List<Control> Controls { get; private set; }
    }
}

OUTPUT:

Count the elements
Number of Elements is: 6

Use when

  • You have a class hierarchy that is effectively sealed.
  • There are many distinct operations to perform on it.
  • The operations are orthogonal to the core purpose of the types in the hierarchy.
  • You need the flexibility to define new operations over time.

Bibliography

Design patterns in C# – part 20 (Observer pattern)

Role

The Observer pattern defines a relationship between objects so that when one changes its state, all the others are notified accordingly.

Design

ObserverPattern

Implementation

  • IObserver -> IStateObserver
  • Observer -> StateObserver
  • Subject -> StatesGenerator
using System;
using System.Collections;
using System.Threading;

namespace ObserverPattern
{
    public class TestObserverPattern
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("---First invoking---\n\n");

            var subject = new StatesGenerator();
            var stateObserverFirst = new StateObserver("First Observer", subject);
            subject.Go();
            subject.Thread.Join();

            Console.WriteLine("\n\n\n\n---Second invoking---\n\n");

            var stateObserverSecond = new StateObserver("Second Observer", subject);
            subject.Go();
            subject.Thread.Join();

            Console.WriteLine("\n\n\n\n---Explicite state changed---\n\n");
            stateObserverFirst.Update("Final State");
            stateObserverSecond.Update("Final State");
        }
    }

    public class StatesGenerator
    {
        #region Delegates

        public delegate void Callback(string message);

        #endregion

        private const int WaitingTime = 500;
        private readonly States _states;

        public StatesGenerator()
        {
            this._states = new States();
        }

        public string SubjectState { get; set; }
        public Thread Thread { get; set; }
        public event Callback Notify;

        public void Go()
        {
            this.Thread = new Thread(this.Run);
            this.Thread.Start();
        }

        private void Run()
        {
            foreach (string s in this._states)
            {
                Console.WriteLine("States Generator: \n\t{0}", s);
                this.SubjectState = s;
                this.Notify(s);
                Thread.Sleep(WaitingTime);
            }
        }

        #region Nested type: States

        private class States : IEnumerable
        {
            private readonly string[] _states = {"State One", "State Two", "State Three"};

            #region IEnumerable Members

            public IEnumerator GetEnumerator()
            {
                foreach (string state in this._states)
                {
                    yield return state;
                }
            }

            #endregion
        }

        #endregion
    }

    public interface IStateObserver
    {
        void Update(string state);
    }

    public class StateObserver : IStateObserver
    {
        private readonly string _name;
        private string _state;

        public StateObserver(string name, StatesGenerator statesGenerator)
        {
            this._name = name;
            statesGenerator.Notify += this.Update;
        }

        #region IStateObserver Members

        public void Update(string subjectState)
        {
            this._state = subjectState;
            Console.WriteLine("{0}: \n\t{1}", this._name, this._state);
        }

        #endregion
    }
}

OUTPUT:

—First invoking—

States Generator:
State One
First Observer:
State One
States Generator:
State Two
First Observer:
State Two
States Generator:
State Three
First Observer:
State Three

—Second invoking—

States Generator:
State One
First Observer:
State One
Second Observer:
State One
States Generator:
State Two
First Observer:
State Two
Second Observer:
State Two
States Generator:
State Three
First Observer:
State Three
Second Observer:
State Three

—Explicite state changed—

First Observer:
Final State
Second Observer:
Final State

Use when

  • There are aspects to an abstraction that can vary independently.
  • Changes in one object need to be propagated to a selection of other objects, not all of them.
  • The object sending the changes does not need to know about the receivers.

Bibliography

Design patterns in C# – part 19 (Mediator pattern)

Role

The Mediator pattern is there to enable objects to communicate without knowing each other’s identities. It also encapsulates a protocol that objects can follow.

Design

MediatorPattern

Implementation

  • Mediator -> MailingListModerator
  • Colleague -> MailWithCopyOwnMessages, MailWithoutCopyOwnMessages (IMail implementation)
using System;

namespace MediatorPattern
{
    public class TestMediatorPattern
    {
        public static void Main(string[] args)
        {
            var moderator = new MailingListModerator();

            var jackMail = new MailWithCopyOwnMessages(moderator, "jacek@mail.com");
            var tomMail = new MailWitoutCopyOwnMessages(moderator, "tom@hotmail.com");
            var michaelMail = new MailWithCopyOwnMessages(moderator, "michael@sunmail.com");

            jackMail.Send("Meeting on Saturday, please all ack");
            tomMail.Send("Ack");

            moderator.Block(tomMail.Receive);

            jackMail.Send("Still waiting some Acks");
            michaelMail.Send("Ack");

            moderator.Unblock(tomMail.Receive);
            jackMail.Send("Thanks all");
        }
    }

    public class MailingListModerator
    {
        #region Delegates

        public delegate void Callback(string message, string form);

        #endregion

        private event Callback Respond;

        public void SignOn(Callback method)
        {
            this.Respond += method;
        }

        public void Block(Callback method)
        {
            this.Respond -= method;
        }

        public void Unblock(Callback method)
        {
            this.Respond += method;
        }

        public void Send(string message, string from)
        {
            if (this.Respond != null)
            {
                this.Respond(message, from);
            }
            Console.WriteLine();
        }
    }

    public interface IMail
    {
        void Receive(string message, string from);
        void Send(string message);
    }

    public class MailWithCopyOwnMessages : IMail
    {
        private readonly MailingListModerator _mailingListModerator;
        protected string _name;

        public MailWithCopyOwnMessages(MailingListModerator mailingListModerator, string name)
        {
            this._mailingListModerator = mailingListModerator;
            this._mailingListModerator.SignOn(this);
            this._name = name;
        }

        #region IMail Members

        public virtual void Receive(string message, string from)
        {
            Console.WriteLine("{0} received from {1}:\n\t{2}", this._name, from, message);
        }

        public void Send(string message)
        {
            Console.WriteLine("Send (From {0}):\n\t{1}", this._name, message);
            this._mailingListModerator.Send(message, this._name);
        }

        #endregion
    }

    public class MailWitoutCopyOwnMessages : MailWithCopyOwnMessages
    {
        public MailWitoutCopyOwnMessages(MailingListModerator mailingListModerator, string name)
            : base(mailingListModerator, name)
        {
        }

        public override void Receive(string message, string from)
        {
            if (!(String.Equals(from, _name)))
            {
                Console.WriteLine("{0} received from {1}: \n\t{2}", _name, from, message);
            }
        }
    }
}

OUTPUT:

Send (From jacek@mail.com):
Meeting on Saturday, please all ack
jacek@mail.com received from jacek@mail.com:
Meeting on Saturday, please all ack
tom@hotmail.com received from jacek@mail.com:
Meeting on Saturday, please all ack
michael@sunmail.com received from jacek@mail.com:
Meeting on Saturday, please all ack
Send (From tom@hotmail.com):
Ack
jacek@mail.com received from tom@hotmail.com:
Ack
michael@sunmail.com received from tom@hotmail.com:
Ack
Send (From jacek@mail.com):
Still waiting some Acks
jacek@mail.com received from jacek@mail.com:
Still waiting some Acks
michael@sunmail.com received from jacek@mail.com:
Still waiting some Acks
Send (From michael@sunmail.com):
Ack
jacek@mail.com received from michael@sunmail.com:
Ack
michael@sunmail.com received from michael@sunmail.com:
Ack
Send (From jacek@mail.com):
Thanks all
jacek@mail.com received from jacek@mail.com:
Thanks all
michael@sunmail.com received from jacek@mail.com:
Thanks all
tom@hotmail.com received from jacek@mail.com:
Thanks all

Use when

  • Objects communicate in well-structured but potentially complex ways.
  • The objects identities should be protected even though they communicate.
  • Some object behavior can be grouped and customized.

Bibliography