Singleton Design Pattern C#

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

namespace TestSingleton
{
    class Program
    {
        static void Main(string[] args)
        {
            Logger logger1 = Logger.GetInstance();
            Logger logger2 = Logger.GetInstance();

            logger1.WriteMessage("This is a message from logger1");
            logger2.WriteMessage("This is a message from logger2");

            //This verifies that there is only one instance was created.
            if (logger1 == logger2)
            {
                Console.WriteLine("Both objects are of the same instance");
            }

            Console.ReadKey();
        }
    }

    /// <summary>
    /// Singleton Class
    /// </summary>
    public sealed class Logger
    {
        //Private Constructor
        private Logger() { }

        //Private instance variable
        private static Logger _loggerInstance = null;

        private static readonly object _threadsafeLock = new object();

        //Method to get instance (With Multithreaded thread safety and Lazy Instantiation)
        public static Logger GetInstance()
        {
            if (_loggerInstance == null)
            {
                lock (_threadsafeLock)
                {
                    _loggerInstance = _loggerInstance ?? new Logger();
                }
            }

            return _loggerInstance;
        }

        /// <summary>
        /// Write message to console or text file based on the requirement.
        /// </summary>
        public void WriteMessage(string message)
        {
            Console.WriteLine(message);
        }
    }
}

Ouptut:
This is a message from logger1
This is a message from logger2
Both objects are of the same instance

Advertisements

Abstract Factory Design Pattern C#

Abstract Factory offers the interface for creating a family of related objects, without explicitly specifying their classes.

AbstractFactory

Florist:

    /// <summary>
    /// Product A
    /// </summary>
    public interface IFlorist { void DecorateFlowers(); }
    
    /// <summary>
    /// Product A1
    /// </summary>
    public class HighBudgetFlorist : IFlorist
    {
        public void DecorateFlowers()
        {
            Console.WriteLine("Florist: Thanks for choosing us to serve...");
        }
    }

    /// <summary>
    /// Product A1
    /// </summary>
    public class LowBudgetFlorist : IFlorist
    {
        public void DecorateFlowers()
        {
            Console.WriteLine("Florist: Thanks for giving us the chance to serve...");
        }
    }

Caterer:

    /// <summary>
    /// Product B
    /// </summary>
    public interface ICaterer { void ServeFood(); }

    /// <summary>
    /// Product B1
    /// </summary>
    public class HighBudgetCaterer : ICaterer
    {
        public void ServeFood()
        {
            Console.WriteLine("Caterer: Thanks for choosing us to serve...");
        }
    }

    /// <summary>
    /// Product B2
    /// </summary>
    public class LowBudgetCaterer : ICaterer
    {
        public void ServeFood()
        {
            Console.WriteLine("Caterer: Thanks for giving us the chance to serve...");
        }
    }

EventOrganiser:

    /// <summary>
    /// Abstract Factory
    /// </summary>
    public interface IEventOrganiser
    {
        IFlorist GetFlorist();
        ICaterer GetCaterer();
    }

    /// <summary>
    /// Concrete factory 1
    /// </summary>
    public class HighBudetEventOrganiser : IEventOrganiser
    {
        public IFlorist GetFlorist()
        {
            return new HighBudgetFlorist();
        }

        public ICaterer GetCaterer()
        {
            return new HighBudgetCaterer();
        }
    }

    /// <summary>
    /// Concrete factory 2
    /// </summary>
    public class LowBudetEventOrganiser : IEventOrganiser
    {
        public IFlorist GetFlorist()
        {
            return new LowBudgetFlorist();
        }

        public ICaterer GetCaterer()
        {
            return new LowBudgetCaterer();
        }
    }

Interacting Client:

    /// <summary>
    /// Interacting Client
    /// </summary>
    public class EventManagementFirm
    {
        IEventOrganiser eventOrganiser;
        public EventManagementFirm(IEventOrganiser _eventOrganiser)
        {
            this.eventOrganiser = _eventOrganiser;
        }

        public void OganiseEvent()
        {
            IFlorist florist = eventOrganiser.GetFlorist();
            ICaterer caterer = eventOrganiser.GetCaterer();

            florist.DecorateFlowers();
            caterer.ServeFood();
        }
    }

Main Method:

static void Main(string[] args)
        {
            IEventOrganiser highProfileEvent = new HighBudetEventOrganiser();   //or LowBudetEventOrganiser
            EventManagementFirm eventManager = new EventManagementFirm(highProfileEvent);
            eventManager.OganiseEvent();
        }

Output:
AbstractFactoryOutput

Factory Method Design Pattern C#

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
FactoryMethodExample

namespace TestFactoryMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            CarFactory carFactory = new SwiftCarFactory();
            ICar car = carFactory.GetCar();
            Console.ReadKey();
        }
    }

    /// <summary>
    /// Product
    /// </summary>
    public interface ICar
    {
        void BuildCar();
    }

    /// <summary>
    /// Concrete Product1
    /// </summary>
    public class SwiftCar : ICar
    {
        public SwiftCar()
        {
            Console.WriteLine("Swift car: Initialized...");
        }

        public void BuildCar()
        {
            Console.WriteLine("Swift car: Building...");
        }

        public void RunSwiftCarQualityCheck()
        {
            Console.WriteLine("Swift car: Quality Check is Successful...");
        }
    }

    /// <summary>
    /// Concrete Product2
    /// </summary>
    public class AltoCar : ICar
    {
        public AltoCar()
        {
            Console.WriteLine("Alto car: Initializing...");
        }

        public void BuildCar()
        {
            Console.WriteLine("Alto car: Building...");
        }

        public void RunAltoCarQualityCheck()
        {
            Console.WriteLine("Alto car: Quality Check is Successful...");
        }
    }

    /// <summary>
    /// Creator
    /// </summary>
    public abstract class CarFactory
    {
        public ICar GetCar()
        {
            ICar car = this.CreateCar();
            return car;
        }

        public abstract ICar CreateCar();
    }

    /// <summary>
    /// Concrete Creator1
    /// </summary>
    public class SwiftCarFactory : CarFactory
    {
        public override ICar CreateCar()
        {
            SwiftCar car = new SwiftCar();
            car.BuildCar();
            car.RunSwiftCarQualityCheck();
            return car;
        }
    }

    /// <summary>
    /// Concrete Creator2
    /// </summary>
    public class AltoCarFactory : CarFactory
    {
        public override ICar CreateCar()
        {
            AltoCar car = new AltoCar();
            car.BuildCar();
            car.RunAltoCarQualityCheck();
            return car;
        }
    }
}

Output:
FactoryMethodOutput

Simple Factory Design Pattern C#

Creates objects without exposing the instantiation logic to the client. Refers to the newly created object through a common interface

SimpleFactory

namespace TestSimpleFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            OperatingSystemFactory osFactory = new OperatingSystemFactory();
            IOperatingSystem windows = osFactory.GetOperatingSytemByType(OperatingSystemType.Windows);
            windows.DisplayWelcomeMessage();
            Console.ReadKey();
        }

        public interface IOperatingSystem
        {
            void DisplayWelcomeMessage();
        }

        public class Windows : IOperatingSystem
        {
            public void DisplayWelcomeMessage()
            {
                Console.WriteLine("Welcome to Windows Operating System");
            }
        }

        public class Linux : IOperatingSystem
        {
            public void DisplayWelcomeMessage()
            {
                Console.WriteLine("Welcome to Linux Operating System");
            }
        }       

        /// <summary>
        /// SimpleFactory
        /// </summary>
        public class OperatingSystemFactory
        {
            public IOperatingSystem GetOperatingSytemByType(OperatingSystemType osType)
            {
                if (osType == OperatingSystemType.Windows)
                {
                    return new Windows();
                }
                else if (osType == OperatingSystemType.Linux)
                {
                    return new Linux();
                }                

                return null;
            }
        }

        public enum OperatingSystemType
        {
            Windows,
            Linux
        }
    }
}

Output:
SimpleFactoryOutput

Facade Design Pattern C#

Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

FacadeDesignPattern (640x480)

Example: We have different formats(ODI, Test and T20 = Subsystems) in cricket and you have a requirement to get sum of total runs scored by a player in each format of cricket. Instead of calling each class method in main, its better to include such complex functionalities in Facade(Cricket) class.

namespace TestFacadePattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Player player = new Player("Sachin");
            Cricket cricket = new Cricket();

            int TotalRuns = cricket.GetAllFormatTotalRunsByPlayer(player);
            Console.WriteLine("Total Runs Scored by {0}: {1}", player.PlayerName, TotalRuns);

            Console.ReadKey();
        }
    }

    public class Player
    {
        private string _playerName;

        //Constructor
        public Player(string playerName)
        {
            this._playerName = playerName;
        }

        public string PlayerName { get { return _playerName; }}
    }

    /// <summary>
    /// SubSystem 1
    /// </summary>
    public class ODICricket
    {
        public int GetTotalRunsByPlayer(Player player)
        {
            //Some Code logic here to get/compute total ODI Score Of a player
            int totalRuns = 15921;
            Console.WriteLine("Total ODI Score Of {0}: {1}", player.PlayerName,totalRuns);
            return totalRuns;
        }
    }

    /// <summary>
    /// SubSystem 2
    /// </summary>
    public class TestCricket
    {
        public int GetTotalRunsByPlayer(Player player)
        {
            //Some Code logic here to get/compute total ODI Score Of a player
            int totalRuns = 18426;
            Console.WriteLine("Total Test Score Of {0}: {1}", player.PlayerName, totalRuns);
            return totalRuns;
        }
    }

    /// <summary>
    /// SubSystem 3
    /// </summary>
    public class T20Cricket
    {
        public int GetTotalRunsByPlayer(Player player)
        {
            //Some Code logic here to get/compute total T20 Score Of a player
            int totalRuns = 10;
            Console.WriteLine("Total T20 Score Of {0}: {1}", player.PlayerName, totalRuns);
            return totalRuns;
        }
    }

    /// <summary>
    /// Facade
    /// </summary>
    public class Cricket
    {
        public int GetAllFormatTotalRunsByPlayer(Player player)
        {
            ODICricket odi = new ODICricket();
            TestCricket test = new TestCricket();
            T20Cricket t20 = new T20Cricket();

            int totalRuns = test.GetTotalRunsByPlayer(player) + odi.GetTotalRunsByPlayer(player) + t20.GetTotalRunsByPlayer(player);
            return totalRuns;
        }
    }
}

Output:
FacadeDesignPattern_Output.JPG

Observer Design Pattern C#

The observer design pattern enables a subscriber to register with and receive notifications from a provider.

Example: There is a product(iPhone6 – Provider) and some customers are interested(subscribers) in buying this product. but they wish to wait for the product price to reduce. so, they will subscribe to the provider and receive update on price changes.

UML:

640px-Observer.svg
By WikiSolvedOwn work, Public Domain, Link

namespace TestObserverPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //Products
            Product iPhone6 = new Product("iPhone6", 65000);
            Product sumsungGalaxyNote5 = new Product("SamsungGalaxyNote5", 48000);

            //Customers interested in iPhone6
            iPhone6.Attach(new InterestedCustomer("Shiva"));
            iPhone6.Attach(new InterestedCustomer("Basava"));

            //Customers interested in SamsungGalaxyNote5
            sumsungGalaxyNote5.Attach(new InterestedCustomer("Ganesh"));
            sumsungGalaxyNote5.Attach(new InterestedCustomer("Rohini"));

            //Procuct price changes (will be notify to the customer)
            iPhone6.Price = 55000;
            sumsungGalaxyNote5.Price = 38000;
            iPhone6.Price = 45000;
            sumsungGalaxyNote5.Price = 28000;

            Console.ReadKey();
        }
    }

    /// <summary>
    /// Subject
    /// </summary>

    public class Product
    {
        private string _productName;
        private double _productPrice;       

        List<IInterestedCustomer> _customers = new List<IInterestedCustomer>();

        public Product(string productName, double productPrice)
        {
            this._productName = productName;
            this._productPrice = productPrice;
        }

        //Attach Customer
        public void Attach(IInterestedCustomer customer)
        {
            _customers.Add(customer);
        }

        //Detach Customer
        public void Detach(IInterestedCustomer customer)
        {
            _customers.Remove(customer);
        }

        //Notify Customer
        public void Notify()
        {
            foreach (IInterestedCustomer customer in _customers)
            {
                customer.InformInterestedCustomer(this);
            }
            Console.WriteLine("---");
        }

        //Set Price (this will cal notify)
        public double Price
        {
            get { return _productPrice; }
            set
            {
                if (_productPrice != value)
                {
                    _productPrice = value;
                    Notify();
                }
            }
        }

        //Get ProductName
        public string ProductName
        {
            get { return _productName; }
        }
    }

    /// <summary>
    /// IObserver
    /// </summary>

    public interface IInterestedCustomer
    {
        void InformInterestedCustomer(Product stock);
    }

    /// <summary>
    /// Observer
    /// </summary>

    public class InterestedCustomer : IInterestedCustomer
    {
        private string _interestedCustomerName;        

        public InterestedCustomer(string interestedCustomerName)
        {
            this._interestedCustomerName = interestedCustomerName;
        }

        public void InformInterestedCustomer(Product stock)
        {
            Console.WriteLine("Notified Customer {0}: {1} price changed to {2}", _interestedCustomerName, stock.ProductName, stock.Price);
        }
    }
}

Output:
ObserverPatternOutput

Hope, The above code and output is self explanatory 🙂