Design Principles


The SOLID Design Principles

https://www.youtube.com/watch?v=Qm8vWgr37OY
What is the Single Responsibility Principle in C#?

The Single Responsibility Principle states that “Each software module or class should have only one reason to change“. In other words, we can say that each module or class should have only one responsibility to do.

So we need to design the software in such a way that everything in a class or module should be related to a single responsibility. That does not mean your class should contain only one method or property, you can have multiple members (methods or properties) as long as they are related to a single responsibility or functionality. So, with the help of SRP, the classes become smaller and cleaner and thus easier to maintain.

Example of without the Single Responsibility Principle in C#:

Please have a look at the following diagram that we want to implement in the following example.

Voilatiing Single Responsibility Principle in C#

As you can see in the above image, we are going to create an Invoice class with four functionalities as Adding and Deleting Invoices, Error Logging as well as Sending Emails. As we are putting all the above four functionalities into a single class or module, we are violating the Single Responsibility Principle. This is because Sending Email and Error Logging are not a part of the Invoice module.

Implementing the SRP in C#

Please have a look at the following diagram.

Single Responsibility Principle in C#

As you can see in the above diagram, now we are going to create three classes. In the invoice class, only the invoice-related functionalities are going to be implemented. The Logger class is going to be used only for logging purposes. Similarly, the Email class is going to handle Email activities. Now each class having only its own responsibilities, as a result, it follows the Single Responsibility Principle in C#.

Open-Closed Principle in C#

Liskov Substitution Principle in C# with a real-time example

https://dotnettutorials.net/lesson/liskov-substitution-principle/

In this article, I am going to discuss the Liskov Substitution Principle in C# with a real-time example. Please read our previous article before proceeding to this article where we discussed the Open-Closed Principle in C# with an example. The Letter L in SOLID stands for Liskov Substitution Principle which is also known as LSP. As part of this article, we are going to discuss the following pointers in detail.

Liskov Substitution Principle in C# with a real-time example
What is the Liskov Substitution Principle?

The Liskov Substitution Principle is a Substitutability principle in object-oriented programming Language. This principle states that, if S is a subtype of T, then objects of type T should be replaced with the objects of type S.

In other words, we can say that objects in an application should be replaceable with the instances of their subtypes without modifying the correctness of that application. 

For example, the father is a teacher whereas his son is a doctor. So here, in this case, the son can’t simply replace his father even though both belong to the same family.

Let us first understand one example without using the Liskov Substitution Principle in C#. In the following example, first, we create the Apple class with the method GetColor. Then we create the Orange class which inherits the Apple class as well as overrides the GetColor method of the Apple class. The point is that an Orange cannot be replaced by an Apple, which results in printing the color of apple as Orange as shown in the below example.

Example without using the Liskov Substitution Principle in C#:
namespace SOLID_PRINCIPLES.LSP
{
    class Program
    {
        static void Main(string[] args)
        {
            Apple apple = new Orange();
            Console.WriteLine(apple.GetColor());
        }
    }
    public class Apple
    {
        public virtual string GetColor()
        {
            return "Red";
        }
    }
    public class Orange : Apple
    {
        public override string GetColor()
        {
            return "Orange";
        }
    }
}
Example Using the Liskov Substitution Principle in C#

Let’s modify the previous example to follow the Liskov Substitution Principle. Here, first, we need a generic base class such as Fruit for both Apple and Orange. Now you can replace the Fruit class object with its subtypes either Apple and Orage and it will behave correctly.

namespace SOLID_PRINCIPLES.LSP
{
    class Program
    {
        static void Main(string[] args)
        {
            Fruit fruit = new Orange();
            Console.WriteLine(fruit.GetColor());
            fruit = new Apple();
            Console.WriteLine(fruit.GetColor());
        }
    }
    public abstract class Fruit
    {
        public abstract string GetColor();
    }
    public class Apple : Fruit
    {
        public override string GetColor()
        {
            return "Red";
        }
    }
    public class Orange : Fruit
    {
        public override string GetColor()
        {
            return "Orange";
        }
    }
}

Now, run the application and it should give the output as expected. Here we are following the Liskov Substitution Principle as we are now able to change the object with its subtype.

Interface Segregation Principle in C#

What is the Interface Segregation Principle in C#?

The Interface Segregation Principle states that “Clients should not be forced to implement any methods they don’t use. Rather than one fat interface, numerous little interfaces are preferred based on groups of methods with each interface serving one submodule“.

Let us break down the above definition into two parts.

  1. First, no class should be forced to implement any method(s) of an interface they don’t use.
  2. Secondly, instead of creating large or you can say fat interfaces, create multiple smaller interfaces with the aim that the clients should only think about the methods that are of interest to them.

What is the Dependency Inversion Principle in C#?

The Dependency Inversion Principle (DIP) states that high-level modules/classes should not depend on low-level modules/classes. Both should depend upon abstractions. Secondly, abstractions should not depend upon details. Details should depend upon abstractions.

The most important point that you need to remember while developing real-time applications, always to try to keep the High-level module and Low-level module as loosely coupled as possible.

When a class knows about the design and implementation of another class, it raises the risk that if we do any changes to one class will break the other class. So we must keep these high-level and low-level modules/classes loosely coupled as much as possible. To do that, we need to make both of them dependent on abstractions instead of knowing each other.

Let’s try simple example with Car and Engine classes, any car need an engine to go anywhere, at least for now. So below how code will look without dependency injection.

public class Car
{
    public Car()
    {
        GasEngine engine = new GasEngine();
        engine.Start();
    }
}

public class GasEngine
{
    public void Start()
    {
        Console.WriteLine("I use gas as my fuel!");
    }
}

And to instantiate the Car class we will use next code:

Car car = new Car();

The issue with this code that we tightly coupled to GasEngine and if we decide to change it to ElectricityEngine then we will need to rewrite Car class. And the bigger the application the more issues and headache we will have to add and use new type of engine.

In other words with this approach is that our high level Car class is dependent on the lower level GasEngine class which violate Dependency Inversion Principle(DIP) from SOLID. DIP suggests that we should depend on abstractions, not concrete classes. So to satisfy this we introduce IEngine interface and rewrite code like below:

    public interface IEngine
    {
        void Start();
    }

    public class GasEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I use gas as my fuel!");
        }
    }

    public class ElectricityEngine : IEngine
    {
        public void Start()
        {
            Console.WriteLine("I am electrocar");
        }
    }

    public class Car
    {
        private readonly IEngine _engine;
        public Car(IEngine engine)
        {
            _engine = engine;
        }

        public void Run()
        {
            _engine.Start();
        }
    }

Now our Car class is dependent on only the IEngine interface, not a specific implementation of engine. Now, the only trick is how do we create an instance of the Car and give it an actual concrete Engine class like GasEngine or ElectricityEngine. That’s where Dependency Injection comes in.

   Car gasCar = new Car(new GasEngine());
   gasCar.Run();
   Car electroCar = new Car(new ElectricityEngine());
   electroCar.Run();

Here we basically inject(pass) our dependency(Engine instance) to Car constructor. So now our classes have loose coupling between objects and their dependencies, and we can easily add new types of engines without changing the Car class.

The main benefit of the Dependency Injection that classes are more loosely coupled, because they do not have hard-coded dependencies. This follows the Dependency Inversion Principle, which was mentioned above. Instead of referencing specific implementations, classes request abstractions (usually interfaces) which are provided to them when the class is constructed.

So in the end Dependency injection is just a technique for achieving loose coupling between objects and their dependencies. Rather than directly instantiating dependencies that class needs in order to perform its actions, dependencies are provided to the class (most often) via constructor injection.

Also when we have many dependencies it is very good practice to use Inversion of Control(IoC) containers which we can tell which interfaces should be mapped to which concrete implementations for all our dependencies and we can have it resolve those dependencies for us when it constructs our object. For example, we could specify in the mapping for the IoC container that the IEngine dependency should be mapped to the GasEngine class and when we ask the IoC container for an instance of our Car class, it will automatically construct our Car class with a GasEngine dependency passed in.

UPDATE: Watched course about EF Core from Julie Lerman recently and also liked her short definition about DI.

Dependency injection is a pattern to allow your application to inject objects on the fly to classes that need them, without forcing those classes to be responsible for those objects. It allows your code to be more loosely coupled, and Entity Framework Core plugs in to this same system of services.

https://stackoverflow.com/questions/130794/what-is-dependency-injection

Dependency Inversion Principle

Which are top 5 common (mostly used) design patterns for C#?

While Paul is correct that design patterns are language agnostic, there are some that are used in C# that you would never realize.

1.) Observer Pattern – This is used heavily in the built in Event System of C#.

2.) Strategy Pattern – List, Array, Dictionary, Char all have a sort method and that sort method chooses the best algorithm for sorting based on the data.

3.) Adapter Pattern – You can look at many of the built in classes that have interfaces that are matched with different interfaces.

4.) Builder Pattern – UWP, WPF and WinForm all utilize this one under the hood.

5.) Singleton Pattern – The Timer class in UWP, WPF, and WinForms all utilize this.

Now that we have the 5 patterns I have chosen, lets define what they are.

Observer: Notify dependent objects of state changes
Strategy: Encapsulate algorithms within a class and make them interchangeable
Adapter Pattern: Match interfaces of classes with different interfaces
Builder Pattern: Separate representation and object construction
Singleton Pattern: Class with only one single possible instance

Definition

Observer pattern is used when there is one to many relationship between objects such as if one object is modified, its dependent objects are to be notified automatically and corresponding changes are done to all dependent objects.

Examples

  1. Let’s say, your permanent address is changed then you need to notify passport authority and pan card authority. So here passport authority and pan card authority are observers and You are a subject.
  2. On Facebook also, If you subscribe to someone then whenever new updates happen then you will be notified.

When to use it:

  1. When one object changes its state, then all other dependents object must automatically change their state to maintain consistency
  2. When the subject doesn’t know about the number of observers it has.
  3. When an object should be able to notify other objects without knowing who objects are.

https://www.c-sharpcorner.com/article/strategy-design-pattern-using-c-sharp/

Explain C# Singleton class with code example – Simple Steps

Below are the steps to design a class as a singleton class in C# programming with program example.

Step -1: First we need to make a constructor of the class private so that object of the class cannot be created outside of the class.

Step -2: Class will have a static method for example static GetInstance() that will be responsible to create object of its own and return to the client program. This method will be static as client cannot create object so client can call using class name only.

Step -3: Design singleton class GetInstance() method so it can return only one object on multiple calls.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SingletonDesignPattern
{
    //Singleton class that returns only one object.
    public class SingleInstanceClass
    {
        //Create a static variable as static method GetInstance() will
        //accept only static variable.
        private static SingleInstanceClass instance = null;

        //Make the constructor private to stop object
        //creation from out side of the class
        private SingleInstanceClass()
        {
        }
        
        //Design GetInstance() method to return only
        //one object on multiple calls
        //@return : Return type is of same class i.e.SingleInstanceClass 
        public static SingleInstanceClass GetInstance()
        {
            //If instance is null then create object of the class
            // and return it or else return the same object.
            if (instance == null)
            {
                instance = new SingleInstanceClass();
            }

            return instance;
        }

        public void Display()
        {
            Console.WriteLine("Single Ton Class Function");
        }

    }

    //CLIENT CODE

    class Program
    {
        static void Main(string[] args)
        {
            //Create 2 objects of the singleton class
            SingleInstanceClass obj1 = SingleInstanceClass.GetInstance();
            obj1.Display();
            SingleInstanceClass obj2 = SingleInstanceClass.GetInstance();
            obj2.Display();

            //Validate if the address of obj1 and obj2 are same.
            //If object.ReferenceEquals() returns  true objects are same
            //or else different.

            //In class is return same object again and again 
            //It will print same objects.
            if (object.ReferenceEquals(obj1, obj2))
            {
                Console.WriteLine("Same objects");
            }
            else
            {
                Console.WriteLine("Different objects");
            }


        }
    }
}
NOTE: Above program source code for C# singleton class is not designed for multi-threaded environment.

Design thread safe Singleton Class in C# Considering Performance

In multi-threaded environment, multiple threads can enter into GetInstance() method’s if condition when object is getting created first time. So, there is chance for more than one object creation. But, singleton class target is to create only one object.

So, we have to put lock in this block so only one thread can enter and create object.

public static SingleInstanceClass GetInstance()
        {                         
             if (instance == null)
             {
                //In multi threaded environment multiple threads can enter
                //here and may create more than one objects.
                 instance = new SingleInstanceClass();
              }               
                       

            return instance;
        }

Let’s put the lock to avoid multiple object creation. Below function design ensures for a single object creation.

public static SingleInstanceClass GetInstance()
        {            
                lock (mutex)
                {                   
                    if (instance == null)
                    {                     
                        instance = new SingleInstanceClass();
                    }
                }                      

            return instance;
        }

But, there is a performance issue now. Let’s say GetInstance() method is getting called again and again during program execution then every time it will check the lock making application slow.

To avoid performance issue, better solution is to put one more if condition to avoid calling locks.

Below piece of code will avoid lock performance issue with singleton thread safe double check concept.

public static SingleInstanceClass GetInstance()
        {
            
            if (instance == null)
            {               
                lock (mutex)
                {
                    //
                    if (instance == null)
                    {
                        //Create
                        instance = new SingleInstanceClass();
                    }
                }
            }           

            return instance;
        }