Principles and Patterns

SOLID Principles

S - Single Responsibility Principle
The single responsibility principle states that every class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.
An important thing to note is that "Martin" defines a responsibility as “a reason to change” so when I think of the single responsibility principle I paraphrase it as a class should have only one reason to change.  When I am designing a system and it is time to start creating classes I always ask myself what things change together and what things change independently of one another.  When I find things that change together they can and often should be put together in the same class when they vary independently, I make sure and separate those things by using different classes.

Example-


public interface IMessage
    {
        IList<String> ToAddresses { get; set; }
        string MessageBody { get; set; }
        bool Send();
    }
    public interface IEmailMessage:IMessage
    {
        string Subject { get; set; }
        IList<String> BccAddresses { get; set; }
    }
    public class SmtpMessage : IEmailMessage
    {
        public IList<String> ToAddresses { get; set; }
        public IList<String> BccAddresses { get; set; }
        public string MessageBody { get; set; }
        public string Subject { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }
    public class SmsMessage : IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
        public bool Send()
        {
            //Do the real work here
            return true;
        }
    }

Now if we Apply the Single Responsibility Principle to our design we recognize that we should not be mixing the Send method with the IMessage interface.  We might come up with something like this:


public interface IMessageServer
    {
        bool Send(IMessage message);
    }
    public interface IMessage
    {
        IList<String> ToAddresses { get; set; }
        string MessageBody { get; set; }
    }
    public interface IEmailMessage : IMessage
    {
        string Subject { get; set; }
        IList<String> BccAddresses { get; set; }
    }
    public class SmtpMessage : IEmailMessage
    {
        public IList<String> ToAddresses { get; set; }
        public IList<String> BccAddresses { get; set; }
        public string MessageBody { get; set; }
        public string Subject { get; set; }
    }
    public class SmsMessage : IMessage
    {
        public IList<String> ToAddresses { get; set; }
        public string MessageBody { get; set; }
    }
    public class SmsMessageServer:IMessageServer
    {
        public bool Send(IMessage message)
        {
            //Do the real work here
            return true;
        }
    }
    public class SmtpMessageServer : IMessageServer
    {
        public bool Send(IMessage message)
        {
            //Do the real work here
            return true;
        }
    }

OOpen Closed Principle
The open closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”.
Example - 
class Customer
{
        private int _CustType;

        public int CustType
        {
            get { return _CustType; }
            set { _CustType = value; }
        }

        public double getDiscount(double TotalSales)
        {
                if (_CustType == 1)
                {
                    return TotalSales - 100;
                }
                else
                {
                    return TotalSales - 50;
                }
        }
}
The problem here is if we add a new customer type we need to go and add one more “IF” condition in the “getDiscount” function, in other words we need to change the customer class.
If we are changing the customer class again and again, we need to ensure that the previous conditions with new one’s are tested again , existing client’s which are referencing this class are working properly as before.
In other words we are “MODIFYING” the current customer code for every change and every time we modify we need to ensure that all the previous functionalities and connected client are working as before.
How about rather than “MODIFYING” we go for “EXTENSION”. In other words every time a new customer type needs to be added we create a new class as shown in the below. So whatever is the current code they are untouched and we just need to test and check the new classes.
class Customer
{
        public virtual double getDiscount(double TotalSales)
        {
            return TotalSales;
        }
}

  class SilverCustomer : Customer
    {
        public override double getDiscount(double TotalSales)
        {
            return base.getDiscount(TotalSales) - 50;
        }
    }
 class goldCustomer : Customer
    {
        public override double getDiscount(double TotalSales)
        {
            return base.getDiscount(TotalSales) - 100;
        }
    }
Putting in simple words the “Customer” class is now closed for any new modification but it’s open for extensions when new customer types are added to the project.

L - Liskov Substitution Principle
The Liskov Substitution Principle states that “Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program”. 
OR
If S is a subtype of T, then objects of type T may be replaced with objects of type S (in other words, objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, and so on).

Understanding the problem
Let us say we have two classes, Rectangle and Square. In this example, the Square class inherits the Rectangle class. Both classes are created as listed below:
public class Rectangle
  {
      public virtual int Height { getset; }
      public virtual int Width { getset; }

  }
The Square class inherits the Rectangle class and overrides the properties as shown in the listing below:
public class Square : Rectangle
  {
      private int _height;
      private int _width;
      public override int Height
      {
          get
          {
              return _height;
          }
          set
          {
              _height = value;
              _width = value;
          }
      }
      public override int Width
      {
          get
          {
              return _width;
          }
          set
          {
             _width = value;
             _height = value;
          }
      }

  }
We need to calculate area of the Rectangle and the Square.  For this purpose, let us create another class called AreaCalculator.
  public class AreaCalculator
        {
            public static int CalculateArea(Rectangle r)
            {
                return r.Height * r.Width;
            }

            public static int CalculateArea(Square s)
            {
                return s.Height * s.Height;
            }
        }
 Let us go ahead and write Unit tests to calculate area of the Rectangle and the Square. A unit test to calculate these areas as shown in the listing below should pass.
        [TestMethod]
        public void Sixfor2x3Rectangle()
        {
            var myRectangle = new Rectangle { Height = 2, Width = 3 };
            var result = AreaCalculator.CalculateArea(myRectangle);
            Assert.AreEqual(6, result);

        }
On the other hand, a test to calculate area of the Square should also pass:
  [TestMethod]
        public void Ninefor3x3Squre()
        {
            var mySquare = new Square { Height = 3 };
            var result = AreaCalculator.CalculateArea(mySquare);
            Assert.AreEqual(9, result);
        }
In the both tests, we are creating:
1.       The Object of Rectangle to find the area of the Rectangle

2.       The Object of Square to find the area of the Square
And the tests pass as expected. Now let us go ahead and create a test in which we will try to substitute the object of Rectangle with the object of Square. We want to find area of Rectangle using the object of Square and for the unit test for this is written below:
  [TestMethod]
        public void TwentyFourfor4x6RectanglefromSquare()
        {
            Rectangle newRectangle = new Square();
            newRectangle.Height = 4;
            newRectangle.Width = 6;
            var result = AreaCalculator.CalculateArea(newRectangle);
            Assert.AreEqual(24, result);
        }
The above test would fail, because the expected result is 24, however the actual area calculated would be 36.

This is the problem. Even though the Square class is a subset of the Rectangle class, the Object of Rectangle class is not substitutable by object of the Square class without causing a problem in the system. If the system adhered to the Lisokov Substitution Principle, you may avoid the above problem.
Solve problem with No-Inheritance
We can solve the above problem by following the below steps:
1.       Get rid of the AreaCalculator class. 
2.       Let each shape define its own Area method. 
3.       Rather than Square class will inherit Rectangle class, let us create a common abstract base class Shape and both classes will inherit that. 
A common base class Shape can be created as shown in listing below:
public  abstract class Shape
        {
        public abstract int Area();

        }
Rectangle and Square class can be modified as shown in the listing below:
public class Rectangle :Shape
  {
      public  int Height { getset; }
      public  int Width { getset; }
      public override int Area()
      {
          return Height * Width;
      }
  }
 public class Square : Shape
  {
      public int Sides;
      public override int Area()
      {
          return Sides * Sides;
      }
  }
Here the above classes are following the Liskov Substitution principle, and we can rewrite the test as shown in the listing below:
 [TestMethod]
        public void TwentyFourfor4x6Rectangleand9for3x3Square()
        {
            var shapes = new List<Shape>{
                new Rectangle{Height=4,Width=6},
                new Square{Sides=3}
            };
            var areas = new List<int>();
         
            foreach (Shape shape in shapes)
            {
                areas.Add(shape.Area());
            }
            Assert.AreEqual(24, areas[0]);
            Assert.AreEqual(9, areas[1]);

        }
In this way we can create relationship between the sub class and the base class by adhering to the Liskov Substitution principle. Common ways to identify violations of LS principles are as follows:
1.       Not implemented method in the sub class.

I- Interface Segregation Principle

According to Wikipedia the interface segregation principle (ISP) states that no client should be forced to depend on methods it does not use.  The interface segregation principle was formulated by Robert Martin in the mid 1990s.
OR
No clients should be forced to implement methods, which it does not use and the contract should be broken into small and more specific intefaces.

Lets explore this with an example:

Now let’s say some clients come up with a demand saying that we want a method which will help us to “Save or Add” customer data. So developer provide like this.
interface IDatabase
{
        void Add(); // old client are happy with these.
}

Now let’s say some new clients come up with a demand saying that we also want a method which will help us to “Read” customer data.So developers would like to change the “IDatabase” interfaceas shown below.
interface IDatabase
{
        void Add(); // old client are happy with these.
voidRead(); // Added for new clients.
}
If you visualize the new requirement which has come up, you have two kinds of client’s: -
  • Who want’s just use “Add” method.
  • The other who wants to use “Add” + “Read”.
Now by changing the current interface you are doing something wrong, disturbing the 1000 satisfied current client’s , even when they are not interested in the “Read” method. You are forcing them to use the “Read” method.
So a better approach would be to keep existing clients seprate and the serve the new client’s separately.
So the better solution would be to create a new interface rather than updating the current interface
interface IDatabaseV1 : IDatabase // Gets the Add method
{
Void Read();
}
You can now create fresh classes which implement “Read” method and satisfy demands of your new clients and your old clients stay untouched and happy with the old interface which does not have “Read” method.
lass CustomerwithRead : IDatabase, IDatabaseV1
    {

public void Add()
{
 Customer obj = new Customer();
Obj.Add();
}
 Public void Read()
 {
 // Implements  logic for read
}
    }
So the old clients will continue using the “IDatabase” interface while new client can use “IDatabaseV1” interface.
IDatabase i = new Customer(); // 1000 happy old clients not touched
i.Add();

IDatabaseV1 iv1 = new CustomerWithread(); // new clients
Iv1.Read();


D- Dependency Inversion Principle

The Dependency Inversion Principle states:  
  • High level modules should not depend upon low level modules. Both should depend upon abstractions.
  • Abstractions should not depend upon details. Details should depend upon abstractions.
The Dependency Inversion principle (DIP) helps to loosely couple your code by ensuring that your high-level modules depend on abstractions rather than concrete implementations of lower-level modules. The Dependency Injection pattern is an application/ implementation of this principle. 

In traditional architecture “Higher” level modules depend on “lower” level modules. If we think in terms of an application with a presentation layer, an application layer, a business layer, and a data layer. The Presentation layer is the highest layer and traditionally depends directly upon and may communicate directly with the Application layer. The application layer is a higher level layer than the Business layer and traditionally depends upon and communicates directly with the business layer and so on.
When the Dependency Inversion Principle is applied this relationship is reversed. The presentation layer defines the abstractions it needs to interact with an application layer. The application layer defines the abstractions it needs from a business layer and the business layer defines the abstractions it needs from a data access layer. That is a key departure from the more classic approach, the higher layer defines the abstractions it needs to do its job and the lower layers implement those abstractions.
Example-
public class Email
{
    public void SendEmail()
    {
        // code
    }
}

public class Notification
{
    private Email _email;
    public Notification()
    {
        _email = new Email();
    }

    public void PromotionalNotification()
    {
        _email.SendEmail();
    }
}
Now Notification class totally depends on Email class, because it only sends one type of notification. If we want to introduce any other like SMS then? We need to change the notification system also. And this is called tightly coupled because Notification class has dependency on Email class. What can we do to make it loosely coupled? Modify the code to below.
public interface IMessage
{
    void SendMessage();
}
public class Email : IMessage
{
    public void SendMessage()
    {
        // code to send email
    }
}

public class SMS : IMessage
{
    public void SendMessage()
    {
        // code to send SMS
    }
}
public class Notification
{
    private IMessage _iMessage;
    public Notification()
    {
        _ _iMessage= new Email();
    }
    public void DoNotify()
    {
        _ _iMessage.SendMessage();
    }
}
IMessage to represent the abstraction, and ensure that the Notification class only calls methods or properties on that interface.
Secondly need to move the creation of the Email class outside of the Notification. We can achieve this by DI pattern.  

Dependency Injection (DI) is a software design pattern that allow us to develop loosely coupled code. DI is a great way to reduce tight coupling between software components. Main point of DI is to free up your classes to better tests and easier maintenance.

There are three basic type of Dependency Injection    Dependency-injection-c-sharp/
  1. Construction Injection
  2. Setter Injection
  3. Interface based Injection.
1. Constructor Injection
public class Notification
{
    private IMessage _iMessage;
    public Notification(IMessage message)
    {
        _iMessage= message;
    }
    public void DoNotify()
    {
        _iMessage.SendMessage();
    }
}
2. Property Injection
public class Notification
{
    private IMessage _message;

    public Notification()
    {
    }
    public IMessage MessageService
    {
       private get;
       set
       {
           _message = value;
       }
     }

    public void DoNotify()
    {
        _message.SendMessage();
    }
}
3. Method Injection
public class Notification
{
    public void DoNotify(IMessage message)
    {
        message.SendMessage();
    }
}

For more https://www.intertech.com/Blog/the-dependency-inversion-principle-with-c-examples/

IOC - So Instead of injecting dependencies manually we can use any container available that will handle all dependencies and scope of that dependency for your application. Below link is one example of Castle Windsor.
Castle-windsor


Singleton Design Pattern

This pattern ensures that a class has only one instance and provides a global point of access to it.

/// <summary>
/// The 'Singleton' class
/// </summary>
class Singleton
{
    private static Singleton _instance;

    // Constructor is 'protected'
    protected Singleton()
    {
    }

    public static Singleton Instance()
    {
        // Uses lazy initialization.
        // Note: this is not thread safe.
        if (_instance == null)
        {
            _instance = new Singleton();
        }

        return _instance;
    }
}

class MainApp
{
    /// <summary>
    /// Entry point into console application.
    /// </summary>
    static void Main()
    {
        //Constructor is protected -- cannot use new
        Singleton s1 = Singleton.Instance();
        Singleton s2 = Singleton.Instance();
        // Test for same instance
        if (s1 == s2)
        {
            Console.WriteLine("Objects are the same instance");
        }
        // Wait for user
        Console.ReadKey();
    }

}

Output - Objects are the same instance


Same task you can achieve with static class but some Practical difference is therebetween
static class and Singleton as below.

Static Class - 

1. static class can not implement interfaces or can not drive from class , it must drive from Object,
2. static class can not passed as a method parameter
3. static class is a sealed class

Singleton Pattern-

1.  Singleton  can  implement interfaces or can drive from class.
2.  Singleton  can  passed as a method parameter
3.. Can not instantiate because of private constructor


The Repository Pattern

Context

In many applications, the business logic accesses data from data stores such as databases, SharePoint lists, or Web services. Directly accessing the data can result in the following:
  • Duplicated code
  • A higher potential for programming errors
  • Weak typing of the business data
  • Difficulty in centralizing data-related policies such as caching
  • An inability to easily test the business logic in isolation from external dependencies

Objectives

Use the Repository pattern to achieve one or more of the following objectives:
  • You want to maximize the amount of code that can be tested with automation and to isolate the data layer to support unit testing.
  • You access the data source from many locations and want to apply centrally managed, consistent access rules and logic.
  • You want to implement and centralize a caching strategy for the data source.
  • You want to improve the code's maintainability and readability by separating business logic from data or service access logic.
  • You want to use business entities that are strongly typed so that you can identify problems at compile time instead of at run time.
  • You want to associate a behavior with the related data. For example, you want to calculate fields or enforce complex relationships or business rules between the data elements within an entity.
  • You want to apply a domain model to simplify complex business logic.

Solution

Use a repository to separate the logic that retrieves the data and maps it to the entity model from the business logic that acts on the model. The business logic should be agnostic to the type of data that comprises the data source layer. For example, the data source layer can be a database, a SharePoint list, or a Web service.
The repository mediates between the data source layer and the business layers of the application. It queries the data source for the data, maps the data from the data source to a business entity, and persists changes in the business entity to the data source. A repository separates the business logic from the interactions with the underlying data source or Web service. The separation between the data and business tiers has three benefits:
  • It centralizes the data logic or Web service access logic.
  • It provides a substitution point for the unit tests.
  • It provides a flexible architecture that can be adapted as the overall design of the application evolves.
There are two ways that the repository can query business entities. It can submit a query object to the client's business logic or it can use methods that specify the business criteria. In the latter case, the repository forms the query on the client's behalf. The repository returns a matching set of entities that satisfy the query. The following diagram shows the interactions of the repository with the client and the data source.

The client submits new or changed entities to the repository for persistence. This pattern demonstrates how to encapsulate several related operations that should be consistent with each other or that have related dependencies. The encapsulated items are sent to the repository for update or delete actions.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.