Mohit Mohit - 2 months ago 7
ASP.NET (C#) Question

Open/Close Principle in OOPS

I am working on a telecom project. I have implemented Open/Closed principle in my project. Below are my classes.

MainServiceClass.CS

public abstract class BaseServiceClass
{
public abstract IEnumerable<string> GetServiceData();
public abstract IEnumerable<string> GetDashBoardData();
}


Web_Service.CS

public class WebServiceClass : BaseServiceClass
{
public override IEnumerable<string> GetServiceData()
{
List<string> MyList = new List<string>();
return MyList;
}

public override IEnumerable<string> GetDashBoardData()
{
List<string> MyList = new List<string>();
return MyList;
}
}


Voice_Service.CS

public class VoiceSericeClass : BaseServiceClass
{
public override IEnumerable<string> GetServiceData()
{
List<string> MyList = new List<string>();
return MyList;
}

public override IEnumerable<string> GetDashBoardData()
{
List<string> MyList = new List<string>();
return MyList;
}
}


In the future, If I need to implement Video service, I will create a new Video_Service class.I believe that I will achieve Open/Close principle.

If I need to add a new method in my MainServiceClass.cs , I will add a new Method (GetNewTypeOfData()).

Question : Here, I am modifying a class. Still, am I following OCP? Or, is there any way to add new method in the MainServiceClass.cs??

Please suggest.

P.S. I need to implement this method in all the derived classes i.e. Web_Service.cs, Voice_Service.cs, and Video_Service.cs


Updating my question after CrudaLilium reply.


This is my understanding. Please correct me if I am wrong.

My Current Code :

public interface IMainBase
{
IEnumerable<string> GetData2016();
}

public class VoiceService : IMainBase
{
public IEnumerable<string> GetData2016()
{
return Enumerable.Empty<string>();
}
}


I would get a new requirement in 2017. So, I will update my code in 2017

public interface IMainBase
{
IEnumerable<string> GetData2016();
}

public class VoiceService : IMainBase
{
public IEnumerable<string> GetData2016()
{
return Enumerable.Empty<string>();
}
}

//New Code will be Added in 2017....Start

public interface IMainBase2017 : IMainBase
{
IEnumerable<string> GetData2017();
}

public class voiceService2017 : VoiceService, IMainBase2017
{
public IEnumerable<string> GetData2017()
{
return Enumerable.Empty<string>();
}
}

//New Code Added be in 2017...Ended


I would again get a new requirement in 2018. So, I will update my code in 2018.

public interface IMainBase
{
IEnumerable<string> GetData2016();
}

public class VoiceService : IMainBase
{
public IEnumerable<string> GetData2016()
{
return Enumerable.Empty<string>();
}
}

//New Code will be Added in 2017....Start

public interface IMainBase2017 : IMainBase
{
IEnumerable<string> GetData2017();
}

public class voiceService2017 : VoiceService, IMainBase2017
{
public IEnumerable<string> GetData2017()
{
return Enumerable.Empty<string>();
}
}

//New Code Added be in 2017...Ended

//New Code will be Added in 2018...Start

public class WebService2018 : IMainBase2017
{
public IEnumerable<string> GetData2016()
{
return Enumerable.Empty<string>();
}

public IEnumerable<string> GetData2017()
{
return Enumerable.Empty<string>();
}
}


//New Code will be Added in 2018...End


As per above code, I am not violating OCP. Is this a good practice or do I have any alternative way also?

Answer

Creating Video_Service is not a problem, but changing BaseServiceClass is and you wouldn't be following the principle.

If you make it abstract you would need to modify all other classes that inherit from BaseServiceClass. But even if you don't make it abstract it seems kinda pointless, because all current client classes that use your BaseServiceClass don't use any other methods except the 2 you already have.

If your client class needs to use 3rd method, it would be better if you make another abstract class (just for example BaseServiceClass2) that will inherit from BaseServiceClass and add the new method there and make your client dependent on this class. From there to extend you existing classes WebServiceClass , VoiceSericeClass you would have to create new class and inherit from BaseServiceClass2 and use adapter pattern.

Example code:

    public abstract class BaseServiceClass
    {
        public abstract IEnumerable<string> GetServiceData();
        public abstract IEnumerable<string> GetDashBoardData();
    }

    public abstract class BaseServiceClass2 : BaseServiceClass
    {
        public abstract IEnumerable<string> GetNewTypeOfData();
    }


    public class WebServiceClass2 : BaseServiceClass2
    {
        private BaseServiceClass adaptee;

        WebServiceClass2(BaseServiceClass adaptee)
        {
            this.adaptee = adaptee;
        }

        public override IEnumerable<string> GetDashBoardData()
        {
            return adaptee.GetDashBoardData();
        }

        public override IEnumerable<string> GetNewTypeOfData()
        {
            return Enumerable.Empty<string>();
        }

        public override IEnumerable<string> GetServiceData()
        {
            return adaptee.GetServiceData();
        }
    }

It would be much better if you make BaseServiceClass an interface and if you need to add anything new you would just creat new interface inhering from it and like in previous example, make your client class dependent on your new interface, from there you could just create new class inheriting from WebServiceClass ,VoiceSericeClass etc. and implement the new interface.

Example:

    public interface IBaseServiceClass
    {
        IEnumerable<string> GetServiceData();
        IEnumerable<string> GetDashBoardData();
    }

    public interface IBaseServiceClass2 : IBaseServiceClass
    {
        IEnumerable<string> GetNewTypeOfData();
    }


    public class WebServiceClass2 : WebServiceClass, IBaseServiceClass2
    {
        public IEnumerable<string> GetNewTypeOfData()
        {
            return Enumerable.Empty<string>();
        }
    }

    public class WebServiceClass : IBaseServiceClass
    {
        public IEnumerable<string> GetServiceData()
        {
            List<string> MyList = new List<string>();
            return MyList;
        }

        public IEnumerable<string> GetDashBoardData()
        {
            List<string> MyList = new List<string>();
            return MyList;
        }
    }

Class/interface names are only used as placeholders and it would be better name them in more meaningful way.