Design Patterns in .NET


“In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.”- wiki

Basically design patterns are reusable solutions to common programming problems.. Patterns are about reusable designs and interactions with objects.
23 Gang of Four (GoF) patterns are generally considered the foundation for all patterns. They are broadly grouped in three groups:
1.       Creational
2.       Structural
3.       Behavioral

Creational Design Pattern
Creational design patterns provide ways to instantiate a single object or group of related objects. Object creation should be done in such a way that, they are separated from their implementing system. It will provide more flexibility in deciding which object needs to be created or instantiated for a given scenario.

There are five creational design patterns,

Abstract Factory, Builder, Factory Method, Prototype and Singleton

I.            Singleton Pattern: - Singleton design pattern ensures that the class has only one instance and provides a global point of access to it. It allows a class to enforce that it is only allocated once.

Scenario: - There is situation in a project where you want only one instance of the object to be and shared among the clients. It is more appropriate than creating a global variable since this may be copied and leads to multiple access points.

Example,
1.       Create sealed class with private constructor
A private constructor is a special instance constructor. It is generally used in classes that contain static members only. If a class has one or more private constructors and no public constructors, other classes (except nested classes) cannot create instances of this class.
2.       Create private static read-only instance of class, Readonly to allows thread-safety
3.       Now create static method which will be used to create instance of class and return it to calling method

        public sealed class Singleton
         {
            Singleton()//Private Consturctor
            {
                // Initialize.
            }

            //Readonly allow thread-safety
            private static readonly Singleton _instance = new Singleton();

            //The public Instance property to allow callers to get the singleton instance.
            public static Singleton Instance
            {
                get
                {
                    return _instance;
                }
            }
            
        }
        class Program
        {
            static void Main()
            {
                Singleton s = Singleton.Instance;
            }
        }

II.            Factory Pattern/Method: - Define an Interface for creating an object but let subclasses decide which class to instantiate. It’s a class that acts as a factory of object instances, meant to construct and create something
With this pattern, we develop an abstraction that isolates the logic for determining which type of class to create.

Scenario: - The best time to use the factory method pattern is when you have multiple different variations of a single entity. For an example you have a button class; this class has different variations, such as ImageButton, InputButton and FlashButton. Depending on the place, you may need to create different buttons. Here you can use a factory to create the buttons.


III.            Abstract Factory Pattern: - Provides an interface for creating families of related or dependent objects without specifying their concrete classes. Abstract Factory patterns acts a super-factory which creates other factories. This pattern is also called as Factory of factories
A factory class helps us to centralize the creation of classes and types. Abstract factory helps us to bring uniformity between related factory patterns which leads more simplified interface for the client.

        public class client//This is a class which use AbstractFactory and AbstractProduct interfaces to create a family of related objects.
        {
            private Packaging _packaging;
            private Delivery _delivery;
            public client(PkgDelvFactory factory)
            {
                _packaging = factory.CreatePackaging();
                _delivery = factory.CreateDelivery();
            }

            public Packaging ClientPackaging
            {
                get { return _packaging; }
            }
            public Delivery ClientDelv
            {
                get { return _delivery; }
            }
        }

        public abstract class Packaging { };//This is an interface which declares a type of product.
        public class StandardPackaging : Packaging { };//This is a class which implements the AbstractProduct interface to create product.
        public class ShockProofPackaging : Packaging { };//This is a class which implements the AbstractProduct interface to create product.

        public abstract class Delivery { };//This is an interface which declares a type of product.
        public class ByPost : Delivery { };//This is a class which implements the AbstractProduct interface to create product.
        public class ByCourier : Delivery { };//This is a class which implements the AbstractProduct interface to create product.

        public abstract class PkgDelvFactory//This is an interface which is used to create abstract product
        {
            public abstract Packaging CreatePackaging();
            public abstract Delivery CreateDelivery();
        }

        public class StandardFactory : PkgDelvFactory//This is a class which implements the AbstractFactory interface to create concrete products.
        {
            public override Packaging CreatePackaging()
            {
                return new StandardPackaging();
            }

            public override Delivery CreateDelivery()
            {
                return new ByPost();
            }
        }

        public class DelicateFactory : PkgDelvFactory//This is a class which implements the AbstractFactory interface to create concrete products.
        {
            public override Packaging CreatePackaging()
            {
                return new ShockProofPackaging();
            }

            public override Delivery CreateDelivery()
            {
                return new ByCourier();
            }
        }


        //Using Abstract Factory
        void GetClientPkgDelvDetails()
        {
            //For Standard and postal delivery
            PkgDelvFactory stdFactory = new StandardFactory();
            client standard = new client(stdFactory);
            string PkgType = standard.ClientPackaging.GetType().ToString();
            string DelvType = standard.ClientDelv.GetType().ToString();

            //For shockproof and courier delivery
            PkgDelvFactory DeliFactory = new DelicateFactory();
            client delicate = new client(DeliFactory);
            PkgType = standard.ClientPackaging.GetType().ToString();
            DelvType = standard.ClientDelv.GetType().ToString();

}


IV.            Prototype Pattern: - This pattern gives us a way to create new objects from the existing instance of the object. Prototype pattern specifies the kind of objects to create using a prototypical instance, and create new objects by copying this prototype. It’s is used to create a duplicate object or clone of the current object to enhance performance.
NOTE:- By setting one object to other object we set the reference of object BYREF, it will not create new object.

If there is an instances when we want the new copy object and changes should not affect the old object, this can be achieved using is prototype patterns.

       public class Customer
        {
            public string strCustomerCode = "";
            public Customer Clone()
            {
                // Shallow Copy: only top-level objects are duplicated
                return (Customer) this.MemberwiseClone();

                // Deep Copy: all objects are duplicated
                //return (Customer)this.Clone();
            }
        }

            Customer obj1 = new Customer();//First copy of object created
            obj1.strCustomerCode = "100";//Set Values

            Customer obj2 = new Customer();//2nd copy of object created
    obj2 = obj2.Clone();//Create copy of object

Difference between shallow copy and deep copy in prototype patterns?
There are two types of cloning for prototype patterns. Shallow cloning & Deep cloning. In shallow copy only that object is cloned, any objects containing in that object is not cloned. To clone all object (class within class) we can use Deep copy. Where we can have clone method written in inner class as well.

V.            Builder Pattern: - In this pattern we separate the construction of a complex object from its representation so that the same construction process can create different representations.
In other words we have to design the system in such a way that the client application will simply specify the parameters that should be used to create the complex object and the builder will take care of building the complex object.
Builder pattern is useful when the construction of the object is very complex.
In this pattern we have,
·         Builder: - Builder is responsible for defining the construction process for individual parts. Builder has those individual processes to initialize and configure the product.
·         Director: - Director takes those individual processes from the builder and defines the sequence to build the product.
·         Product: - Product is the final object which is produced from the builder and director coordination.

For more understanding please check below sample code snippet; I have added comments inline for better understanding

        public interface IBuilder//This is an interface which is used to define all the steps to create a product
        {
            void BuildPart1();
            void BuildPart2();
            void BuildPart3();
            Product GetProduct();
        }

        public class ConcreteBuilder : IBuilder//This is a class which implements the Builder interface to create complex product.
        {
            private Product _product = new Product();
            public void BuildPart1()
            {
                _product.Part1 = "Part 1";
            }
            public void BuildPart2()
            {
                _product.Part2 = "Part 2";
            }
            public void BuildPart3()
            {
                _product.Part3 = "Part 3";
            }
            public Product GetProduct()
            {
                return _product;
            }
        }
        public class Director//This is a class which is used to construct an object using the Builder interface.
        {
            public void Construct(IBuilder IBuilder)
            {
                IBuilder.BuildPart1();
                IBuilder.BuildPart2();
                IBuilder.BuildPart3();
            }
        }
        public class Product//This is a class which defines the parts of the complex object which are to be generated by the builder pattern.
        {
            public string Part1 { get; set; }
            public string Part2 { get; set; }
            public string Part3 { get; set; }
 }


For Structural design pattern please refer next article.
https://dotnetlearningarray.blogspot.com/2018/06/structural-design-patterns.html


Comments