Open Close Principle(OCP)

In My previous post I have explained the implementation of Single Responsibility Principle (SRP) using c#. Here I would like to provide Open Close Principle(OCP) using c#. As per this design principle application should be able to extend the code & should not be allow for Modification.

“Software application source codes should be open for extension but should be closed for modification.”
Please find the below Code:                      

/// <summary>
    /// Car Object
    /// </summary>
    public class Car
    {
        public string Name { get; set; }
    }
    /// <summary>
    /// Calculating Mileage for each car
    /// </summary>
    public class MileageCalculator
    {
        IEnumerable<Car> _cars;
        public MileageCalculator(IEnumerable<Car> cars)
        {
            this._cars = cars;
        }
        public void CalculateMileage()
        {
            foreach (var car in _cars)
            {
                if (car.Name == "Maruthi")
                    Console.WriteLine("Mileage of the car {0} is {1}", car.Name, "10M");
                else if (car.Name == "Ford")
                    Console.WriteLine("Mileage of the car {0} is {1}", car.Name, "20M");
            }
        }
    } 
 The above code snippet is following SRP principle. But it is completely concrete. Ie if we needs to change the mileage of a car we needs to change the implementation. This is against the OCP rule of Design. You can see the call of the implementation.

Invoke the Implementation

     List<Car> lstCar = new List<Car>();
            lstCar.Add(new Car { Name = "Maruthi" });
            lstCar.Add(new Car { Name = "Ford" });
            MileageCalculator mlc = new MileageCalculator(lstCar);
            mlc.CalculateMileage();
 
Open Close Principle implementation 

/// <summary>
    ///  Calculating Mileage for each car
    /// </summary>
    public class MileageCalculator
    {
        IEnumerable<ICar> _cars;
        public MileageCalculator(IEnumerable<ICar> cars)
        {
            this._cars = cars;
        }
        public void CalculateMileage()
        {
            CarController controller = new CarController(_cars);
            foreach (var car in _cars)
            {
                Console.WriteLine("Mileage of the car {0} is {1}", car.Name, controller.GetCarMileage(car.Name));
            }
        }
    }
    /// <summary>
    /// Car controller Class
    /// </summary>
    public class CarController
    {
        public IEnumerable<ICar> cars;
        public CarController(IEnumerable<ICar> icars)
        {
            cars = icars;
        }
        public string GetCarMileage(string name)
        {
           return cars.First(car => car.Name.Equals(name)).GetMileage();
        }
    }
    /// <summary>
    /// Interface for Car
    /// </summary>
    public interface ICar
    {
        string Name { get; set; }
        string Mileage { get; set; }
        string GetMileage();
    }
    /// <summary>
    /// Creating different Class(Ford)
    /// </summary>
    public class Ford : ICar
    {
        public string Name
        {
            get;
            set;
        }
        public string Mileage
        {
            get;
            set;
        }
        public string GetMileage()
        {
            return Mileage;
        }
    }
    /// <summary>
    ///  Creating different Class(Maruthi)
    /// </summary>
    public class Maruthi : ICar
    {
        public string Name
        {
            get;
            set;
        }
        public string Mileage
        {
            get;
            set;
        }
        public string GetMileage()
        {
            return Mileage;
        }
    }

Here I have split the Car objects to more generalized way, class “Car” moved to ‘Ford’ & ‘Maruthi’ with the help of “ICar” Interface.  I have added new Property & one method for Getting Mileage.
Invoke the Implementation

List<ICar> lstCar = new List<ICar>();
            lstCar.Add(new Maruthi { Name = "Maruthi" , Mileage="20Km" });
            lstCar.Add(new Ford { Name = "Ford" ,Mileage = "15km"});
            MileageCalculator mlc = new MileageCalculator(lstCar);
            mlc.CalculateMileage();
 
There is no much difference in invoking the implementation. Only needs to add Mileage property in initialization.

You may think that how it allow extension without modifying the source code. Assume that you needs to add one more car object like “Fiat” What are the thinks needs to do?.
Add One More Class in to the same Namespace Like the below

/// <summary>
    /// Creating different Class(Fiat)
    /// </summary>
    public class Fiat : ICar
    {
        public string Name
        {
            get;
            set;
        }
        public string Mileage
        {
            get;
            set;
        }
        public string GetMileage()
        {
            return Mileage;
        }
    }

Add One more Object in the invoke call Like below . Instead of this one we can make Car object as configurable in Config or XML File.
     List<ICar> lstCar = new List<ICar>();
            lstCar.Add(new Maruthi { Name = "Maruthi" , Mileage="20Km" });
            lstCar.Add(new Ford { Name = "Ford" ,Mileage = "15km"});
            lstCar.Add(new Fiat { Name = "Fiat", Mileage = "18 KM" });
            MileageCalculator mlc = new MileageCalculator(lstCar);
            mlc.CalculateMileage();

No comments:

Post a Comment