Archive for February, 2014

In the above video, Jamie King of computersciencevideos.org explained singleton pattern and its comparison with static class in an elegant manner.

The singleton pattern is a design pattern that restricts the instantiation of a class to one object.

This is useful when exactly one object is needed to coordinate actions across the system. For example, we only need only once instance of logging file. One instance can be shared across multitude of other clients.

Definition

Ensure a class has only one instance and provide a global point of access to it.

Participants

The classes and/or objects participating in this pattern are:

  • Singleton   (LoadBalancer/Logger)
    • Defines an Instance operation that lets clients access its unique instance. Instance is a class operation.
    • Responsible for creating and maintaining its own unique instance.

Sample Code:

namespace SingletonPattern
{
    class Logger
    {
        private static Logger _logger;

        private Logger(){}

        public static Logger GetInstance()
        {
            if (_logger == null)
            {
                _logger = new Logger();
            }

                return _logger;

        }

        public void WriteToFile()
        {
            //Add code to write to a file
            Console.WriteLine("Wrote to a file");
        }

    }
}

namespace SingletonPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Logger log = Logger.GetInstance();
            log.WriteToFile();
            Console.ReadKey();
        }
    }
}

Another Example


// Singleton pattern -- .NET optimized

using System;
using System.Collections.Generic;

namespace DoFactory.GangOfFour.Singleton.NETOptimized
{
    /// <summary>
    /// MainApp startup class for .NET optimized
    /// Singleton Design Pattern.
    /// </summary>
    class MainApp
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>
        static void Main()
        {
            LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
            LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
            LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
            LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

            // Confirm these are the same instance
            if (b1 == b2 && b2 == b3 && b3 == b4)
            {
                Console.WriteLine("Same instance\n");
            }

            // Next, load balance 15 requests for a server
            LoadBalancer balancer = LoadBalancer.GetLoadBalancer();
            for (int i = 0; i < 15; i++)
            {
                string serverName = balancer.NextServer.Name;
                Console.WriteLine("Dispatch request to: " + serverName);
            }

            // Wait for user
            Console.ReadKey();
        }
    }

    /// <summary>
    /// The 'Singleton' class
    /// </summary>
    sealed class LoadBalancer
    {
        // Static members are 'eagerly initialized', that is,
        // immediately when class is loaded for the first time.
        // .NET guarantees thread safety for static initialization
        private static readonly LoadBalancer _instance =
          new LoadBalancer();

        // Type-safe generic list of servers
        private List<Server> _servers;
        private Random _random = new Random();

        // Note: constructor is 'private'
        private LoadBalancer()
        {
            // Load list of available servers
            _servers = new List<Server>
        {
         new Server{ Name = "ServerI", IP = "120.14.220.18" },
         new Server{ Name = "ServerII", IP = "120.14.220.19" },
         new Server{ Name = "ServerIII", IP = "120.14.220.20" },
         new Server{ Name = "ServerIV", IP = "120.14.220.21" },
         new Server{ Name = "ServerV", IP = "120.14.220.22" },
        };
        }

        public static LoadBalancer GetLoadBalancer()
        {
            return _instance;
        }

        // Simple, but effective load balancer
        public Server NextServer
        {
            get
            {
                int r = _random.Next(_servers.Count);
                return _servers[r];
            }
        }
    }

    /// <summary>
    /// Represents a server machine
    /// </summary>
    class Server
    {
        // Gets or sets server name
        public string Name { get; set; }

        // Gets or sets server IP address
        public string IP { get; set; }
    }
}

A strategy is a plan of action designed to achieve a specific goal.

Definition

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

UML class diagram

st_1

Participants

The classes and/or objects participating in this pattern are:

  • Strategy  (SortStrategy)
    • Declares an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a ConcreteStrategy
  • ConcreteStrategy  (QuickSort, ShellSort, MergeSort)
    • implements the algorithm using the Strategy interface
  • Context  (SortedList)
    • is configured with a ConcreteStrategy object
    • maintains a reference to a Strategy object
    • may define an interface that lets Strategy access its data.
Code Sample

IStrategy Interface & Discount Algorithm implementation

st_2
namespace StrategyPattern
{
    public interface IStrategy
    {
        int FinalBill(int billAmmount);

    }
}

namespace StrategyPattern
{
    public class HighDiscountStrategy : IStrategy
    {

        public int FinalBill(int billAmmount)
        {
            return (int)(billAmmount - (billAmmount * 0.5));
        }
    }
}

namespace StrategyPattern
{
    public class LowDiscountStrategy : IStrategy
    {
        public int FinalBill(int billAmmount)
        {
            return (int)(billAmmount - (billAmmount * 0.1));
        }
    }
}

namespace StrategyPattern
{
    public class NoDiscountStrategy : IStrategy
    {

        public int FinalBill(int billAmmount)
        {
            return billAmmount;
        }
    }
}

namespace StrategyPattern
{
    public class ShoppingMall
    {
        public string CustomerName { get; set; }
        public int BillAmount { get; set; }
        public IStrategy CurrentStrategy;

        public ShoppingMall(IStrategy strategy)
        {
            CurrentStrategy = strategy;
        }

        public int FinallBill()
        {
            return CurrentStrategy.FinalBill(BillAmount);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        //Monday Customer
        var mall = new ShoppingMall(new LowDiscountStrategy())
        {
            CustomerName = "Kishore",
            BillAmount = 10000
        };

        Console.WriteLine(" Total Bill Amount :" + mall.BillAmount);
        Console.WriteLine(" Final Bill to be paid after discount :" + mall.FinallBill());

        //Wednesday Customer
        var mall1 = new ShoppingMall(new HighDiscountStrategy())
        {
            CustomerName = "Borra",
            BillAmount = 10000
        };

        Console.WriteLine(" Total Bill Amount :" + mall1.BillAmount);
        Console.WriteLine(" Final Bill to be paid after discount :" + mall1.FinallBill());

        //Sunday Customer
        var mall2 = new ShoppingMall(new NoDiscountStrategy())
        {
            CustomerName = "Borra",
            BillAmount = 10000
        };

        Console.WriteLine(" Total Bill Amount :" + mall2.BillAmount);
        Console.WriteLine(" Final Bill to be paid after discount :" + mall2.FinallBill());

        Console.ReadLine();

    }
}