Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Learning the S.O.L.I.D Programming Principles: Open Closed Principle [Part - III]

0.00/5 (No votes)
25 Oct 2014 1  
Open closed principle

History

In our previous posts, we learned ‘What is S.O.L.I.D. Programming Principles’ and a detailed explanation with code of Single Responsibility Principle.

S.O.L.I.D. is an acronym introduced by Michael Feathers as:

  1. S for SRP: Single responsibility principle
  2. O for OCP: Open/closed principle
  3. L for LSP: Liskov substitution principle
  4. I for ISP: Interface segregation principle
  5. D for DIP: Dependency inversion principle

Single Responsibility Principle says, class should have single responsibility. In reference to this, I would say “A class should have single responsibility”.

Let's dive into the ocean – can we read this like “a class should not design to do multiple activities”.

This is a very vast topic and it is not possible to learn/explain it in a one-shot. I divided this into the following parts:

Introduction

In this whole article, we will learn Open Closed Principle in details with example.

First of all, let's revise what is OCP [ref. to Learning The S.O.L.I.D Programming Principles: Overview [Part - I]]?

A definition from wiki:

Quote:

software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification

Learning Open/Closed Principle (OCP)

I took many weeks to understand this principle and when I visited my old code, I was shocked to see that I violate OCP in many of my previously written codes.

Let's explore this with an example: we need to update our database from one server to another server (suppose we need to refresh our development database from production), but there are some rules like data-type should be the same, data value should be changed, etc.

C#
public class ValidateData
{
    public void SyncronizeData(ServerData data, SourceServerData sourceData)
    {
        if (IsValid(data, sourceData))
        {
            //save data
        }
    }

    private bool IsValid(ServerData data, SourceServerData sourceData)
    {
        var result = false;

        if (data.Type == sourceData.Type)
            result = true;

        if (data.IP != sourceData.IP)
            result = true;

        //other checks/rules to validate incoming data

        return result;
    }
}

Wait here to think about what is wrong with the above code…

Any guesses…

Ok, let's discuss now, take a look into class ValidateData. First of all, it is doing two activities, in other words, our class is responsible for two things:

  • to validate incoming data (from source server)
  • to save data

Now, think of a scenario, if someone wants to extend this so, it could use another external service. In this scenario, he/she would have no other choice and have to modify IsValid method. Also, if someone needs to make it as a component and provide to third parties for their use, then its users would have no way to add another service. This means this class is not open for extensions. On the other hand, if someone needs to modify the behavior to persist data, she/he needs to change the actual class.

To sum up, this class is directly violating OCP as this is neither open for extensions not closed for modifications.

So, what would be a better solution for this class so it should follow, OCP.

Remember abstraction, let's try to do something by creating an interface:

C#
public interface IDataValidator
{
    bool Validate(ServerData data, SourceServerData sourceData);
}

Here, I created an interface IDataValidator which is having only one method Validate. Method name describes itself, it's a part of DataValidator so, it should validate data so, it named as Validate :).

Now, create validators of type IDataValidator. Something like:

C#
public class IPValidator : IDataValidator
{
    public bool Validate(ServerData data, SourceServerData sourceData)
    {
        return data.IP != sourceData.IP;
    }

}
public class TypeValidator : IDataValidator
{
    public bool Validate(ServerData data, SourceServerData sourceData)
    {
        return data.Type == sourceData.Type;
    }
}

Forget redesign our class ValidateData as:

C#
public class ValidateData
{
    public bool IsDataValidated(ServerData data, SourceServerData sourceData)
    {
        IList<IDataValidator> validators = new List<IDataValidator>();
        validators.Add(new IPValidator());
        validators.Add(new TypeValidator());

        return IsDataValid(validators, data, sourceData);
    }

    private bool IsDataValid(IList<IDataValidator> validators,
                             ServerData data, SourceServerData sourceData)
    {
        foreach (var validator in validators)
        {
            if (validator.Validate(data, sourceData))
                return true;
        }
        return false;
    }
}

Stay here to discuss the above snippet! In the above, we have a ValidateData class, which is only responsible for validating data by certain validations/rules.

With the above changes, our class is not more stable and robust, we can add many validators as we want. Also, you can use this validator to save your data.

Ah! I forget to mention, you can save the data just by calling this validator to another class, it could be repository class or your custom class where you just persist your data.

I am not going to write that part of save, you can easily implement this by yourself. :)

Revisiting – Learning The S.O.L.I.D Programming Principles: Open Closed Principle [Part - III]

Open Closed Principle says “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”

How to Download the Source Code?

You can download complete souce code of examples used in this article from GitHub: Learning Solid.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here