Pages

Principles and Patterns

SOLID Principles

S - Single Responsibility PrincipleThe 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-

publicinterfaceIMessage

{

IList<String>ToAddresses{get;set;}

stringMessageBody{get;set;}

boolSend();

}

publicinterfaceIEmailMessage:IMessage

{

stringSubject{get;set;}

IList<String>BccAddresses{get;set;}

}

publicclassSmtpMessage:IEmailMessage

{

publicIList<String>ToAddresses{get;set;}

publicIList<String>BccAddresses{get;set;}

publicstringMessageBody{get;set;}

publicstringSubject{get;set;}

publicboolSend()

{

//Do the real work here

returntrue;

}

}

publicclassSmsMessage:IMessage

{

publicIList<String>ToAddresses{get;set;}

publicstringMessageBody{get;set;}

publicboolSend()

{

//Do the real work here

returntrue;

}

}

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:

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.

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:

publicclassRectangle

{

publicvirtualint Height { get; set; }

publicvirtualint Width { get; set; }

}

The Square class inherits the Rectangle class and overrides the properties as shown in the listing below:

publicclassSquare : Rectangle

{

privateint _height;

privateint _width;

publicoverrideint Height

{

get

{

return _height;

}

set

{

_height = value;

_width = value;

}

}

publicoverrideint 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.

publicclassAreaCalculator

{

publicstaticint CalculateArea(Rectangle r)

{

return r.Height * r.Width;

}

publicstaticint 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]

publicvoid Sixfor2x3Rectangle()

{

var myRectangle = newRectangle { 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]

publicvoid Ninefor3x3Squre()

{

var mySquare = newSquare { 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]

publicvoid TwentyFourfor4x6RectanglefromSquare()

{

Rectangle newRectangle = newSquare();

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:

publicabstractclassShape

{

publicabstractint Area();

}

Rectangle and Square class can be modified as shown in the listing below:

publicclassRectangle :Shape

{

publicint Height { get; set; }

publicint Width { get; set; }

publicoverrideint Area()

{

return Height * Width;

}

}

publicclassSquare : Shape

{

publicint Sides;

publicoverrideint 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]

publicvoid TwentyFourfor4x6Rectangleand9for3x3Square()

{

var shapes = newList<Shape>{

newRectangle{Height=4,Width=6},

newSquare{Sides=3}

};

var areas = newList<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:

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.

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.

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

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.

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.

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.

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

///<summary>

/// The 'Singleton' class

///</summary>

classSingleton

{

privatestaticSingleton _instance;

//
Constructor is 'protected'

protected Singleton()

{

}

publicstaticSingleton Instance()

{

//
Uses lazy initialization.

//
Note: this is not thread safe.

if (_instance == null)

{

_instance = newSingleton();

}

return _instance;

}

}

classMainApp

{

///<summary>

/// Entry point into
console application.

///</summary>

staticvoid 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.