DEV Community

Cover image for Creational Design Patterns In C#
Bardia Mostafavi
Bardia Mostafavi

Posted on

Creational Design Patterns In C#

What is a Design Pattern !?

In a simple word , Design Pattern is a standard solution for handling specific situation. thus you can use it to save your time so do not have to reinvent the wheel, and most important of that you use it because this is standard and optimum solution and approved by all other real programmers. just what you need is to check the situation and pick a best and relevant design pattern and adjust it for using in your code. but keep in mind do not use them everywhere, sometime simple code do the work better and no need for overusing of Design Patterns.

Basically, there are three main categories in Design Patterns :

  1. Creational
  2. Structural
  3. Behavioral

Creational Design Patterns are mainly focused on creation of objects. So for example they can make creation of big object easy and reusable. there are five different patterns exist in Creational category with different usage :

  1. Abstract Factory
  2. Factory Method
  3. Builder
  4. Prototype
  5. Singleton

Abstract Factory

This pattern use for creating of families of related objects so we have interface or abstract class as factory which have multiple methods that usually return related type.

First make some related type :

    public interface ITechCompany
    {
        void PrintDetail();
    }
    public interface ICarCompany
    {
        void PrintDetail();
    }
    //family #1
    public class Asus : ITechCompany
    {
        public void PrintDetail()
        {
            Console.WriteLine("i am detail of asus company");
        }
    }
    public class Dell : ITechCompany
    {
        public void PrintDetail()
        {
            Console.WriteLine("i am detail of dell company");
        }
    }
    //family #2
    public class Benz : ICarCompany
    {
        public void PrintDetail()
        {
            Console.WriteLine("i am detail of Benz company");
        }
    }
    public class Audi : ICarCompany
    {
        public void PrintDetail()
        {
            Console.WriteLine("i am detail of Audi company");
        }
    }
Enter fullscreen mode Exit fullscreen mode

Second implement of the Pattern :

    public interface ICompanyFactory
    {
        ITechCompany CreateTechCompany();
        ICarCompany CreateCarCompany();
    } 
    public class CompanyFactoryA : ICompanyFactory
    {
        public ITechCompany CreateTechCompany()
        {
            return new Asus();
        }
        public ICarCompany CreateCarCompany()
        {
            return new Benz();
        }
    }
    public class CompanyFactoryB : ICompanyFactory
    {
        public ITechCompany CreateTechCompany()
        {
            return new Dell();
        }
        public ICarCompany CreateCarCompany()
        {
            return new Audi();
        }
    }
    public static class AbstractFactoryExample
    {
        public static void Test()
        {
            var factoryA = new CompanyFactoryA();
            var carA = factoryA.CreateCarCompany();
            var techA = factoryA.CreateTechCompany();
            carA.PrintDetail(); 
            techA.PrintDetail();

            var factoryB = new CompanyFactoryB();
            var carB = factoryB.CreateCarCompany();
            var techB = factoryB.CreateTechCompany();
            carB.PrintDetail();
            techB.PrintDetail();
        }
        //result :
        //i am detail of Benz company
        //i am detail of asus company
        //i am detail of Audi company
        //i am detail of dell company
    }
Enter fullscreen mode Exit fullscreen mode

Factory Method

To be honestly , factory method pattern is like abstract factory but with difference in one thing , abstract factory is an object with a multiple factory method , you can use this method for high flexibility.

implement of the Pattern (we are using family types that we have been declared earlier):

    public interface ITechCompanyCreator
    {
        ITechCompany CreateTechCompany();
    }
    public class TechCompanyCreatorA : ITechCompanyCreator
    {
        public ITechCompany CreateTechCompany()
        {
            return new Asus();
        }
    }
    public class TechCompanyCreatorB : ITechCompanyCreator
    {
        public ITechCompany CreateTechCompany()
        {
            return new Dell();
        }
    }
    public static class FactoryMethodExample
    {
        public static void Test()
        {
            var creatorA = new TechCompanyCreatorA();
            var techA = creatorA.CreateTechCompany();
            techA.PrintDetail();

            var creatorB = new TechCompanyCreatorB();
            var techB = creatorB.CreateTechCompany();
            techB.PrintDetail();
        }
        //result :
        //i am detail of Asus company
        //i am detail of Dell company
    }
Enter fullscreen mode Exit fullscreen mode

Builder

This pattern use for creating big object with lots of possible configuration.

    public interface IBuilder
    {
        Contact Build();
    }
    public class ContactBuilder : IBuilder
    {
        private readonly Contact _contact = new Contact();
        public ContactBuilder WithName(string name)
        {
            _contact.Name = name;
            return this;
        }
        public ContactBuilder WithFamily(string family)
        {
            _contact.Family = family;
            return this;
        }
        public ContactBuilder WithAge(int age)
        {
            _contact.Age = age;
            return this;
        }
        public Contact Build()
        {
            return _contact;
        }
    }
    public class Contact
    {
        public string Name { get; set; }
        public string Family { get; set; }
        public int Age { get; set; }
    }
    public static class BuilderExample
    {
        public static void Test()
        {
            var contact = new ContactBuilder()
                          .WithName("name")
                          .WithFamily("family")
                          .WithAge(10)
                          .Build();
            Console.WriteLine(contact.ToJson());
        }      
        //result :
        //{"Name":"name","Family":"family","Age":10}
    }
Enter fullscreen mode Exit fullscreen mode

Prototype

This pattern use for taking clone of any object with any complexity with decoupling clone from origin object.

    public class Person
    {
        public string Name { get; set; }
        public Family Family { get; set; }
        public int Age { get; set; }

        //Pattern        
        public Person ShallowCopy()
        {
            return (Person) this.MemberwiseClone();
        }
        public Person DeepCopy()
        {
            var clone =  (Person) this.MemberwiseClone();
            clone.Name = new string(Name);
            clone.Family = new Family
            {
                MiddleName = new string(Family.MiddleName),
                LastName = new string(Family.LastName)
            };
            return clone;
        }    
    }
    public class Family
    {
        public string MiddleName { get; set; }
        public string LastName { get; set; }
    }

    public static class PrototypeExample
    {

        public static void Test()
        {
            var person = new Person
            {
                Name = "David",
                Family = new Family
                {
                    MiddleName = "Junior",
                    LastName = "Nolan"
                },
                Age = 20
            };

            var shallowCopied = person.ShallowCopy();
            var deepCopied = person.DeepCopy();

            person.Age = 55;
            person.Name = "rookie";
            person.Family.LastName = "bishop";

            Console.WriteLine(person.ToJson());
            Console.WriteLine(shallowCopied.ToJson());
            Console.WriteLine(deepCopied.ToJson());
        }

        //result:
        //{"Name":"rookie","Family":{"MiddleName":"Junior","LastName":"bishop"},"Age":55}  => person
        //{"Name":"David","Family":{"MiddleName":"Junior","LastName":"bishop"},"Age":20}  => shallowcopy
        //{"Name":"David","Family":{"MiddleName":"Junior","LastName":"Nolan"},"Age":20}  => deepcopy
    }
Enter fullscreen mode Exit fullscreen mode

Singleton

With this pattern we ensure that we have one instance of object in runtime with one general global access.

    public class Singleton
    {
        private Singleton()
        {
        }

        private static Singleton _instance;

        public static Singleton GetInstance()
        {
            if (_instance == null)
                _instance = new Singleton();
            return _instance;
        }
    }
    public static class SingletonExample
    {
        public static void Test()
        {
            var instance1 = Singleton.GetInstance();
            var instance2 = Singleton.GetInstance();

            if (instance1.Equals(instance2))
                Console.WriteLine("Yes");
            else
                Console.WriteLine("No");
        }
        //result:
        //Yes
    }
Enter fullscreen mode Exit fullscreen mode

Ok , That's enough, now you know about the basic of creational patterns , i will explain two other categories in two different articles later.

Discussion (4)

Collapse
alwaysmaap profile image
Mohammad ali Ali panah

great job <333

Collapse
mstbardia profile image
Bardia Mostafavi Author

thanks bro <3.

Collapse
ashokraju105605 profile image
ashokraju105605

Please share for structural also in c#. This one is short and precise

Collapse
mstbardia profile image
Bardia Mostafavi Author

thanks for your feedback , Structural Design Patterns In C# has been published.