S.O.L.I.D Principles for beginners (Part 2)

Before starting, please click here to view Part 1 of this blog post, if you have not read it.

Open / Closed Principle
Definition: An entity should be open for extension, but closed for modification.

Scenario: Let’s talk about the same logistics application created for Mr. X. We have a shipment module which process the shipment. Mr. X then requested for an international shipment module to be added with the existing application. We can directly add the condition using an if… else statement. But, what If he needs another module to be added? Say, a region shipment. Here Process shipment is not open for extension.
Solution: Add a new interface IShipment which has the process shipment method. 

public interface IShipment
{
    void ProcessShipment(ICustomerDetails customerDetails);
}

/// <summary>
/// Adding IShipent interface is considered as an open close principle and 
/// adding ICustomer details as parameter is to avoid violating Single Responsibility of shipment
/// </summary>
public class LocalShipment : IShipment
{
    public void ProcessShipment(ICustomerDetails customerDetails)
    {
        Console.WriteLine("Process local shipment for " + customerDetails.CustomerName);
    }
}

/// <summary>
/// Liskov Substitution Principle: Derived classes should extend the base classes without changing their behavior
/// Adding  a new parameter Discount in internationl shipment is a classic example of 
/// Liskov Substitution Principle; This is explained in the next blog post.
/// </summary>
public class InternationalShipment : IShipment
{
    private InternationalAgent Agent { get; set; }

    public InternationalShipment(InternationalAgent agent)
    {       
        this.Agent = agent;
    }

    public void ProcessShipment(ICustomerDetails customerDetails)
    {
        if (this.Agent == null)
        {
            // Derived classes should extend the base classes without changing their behavior
            // If we return from the method, the base class behavior is changed. 
            // i.e Process shipment has not achieved its functionality
            // This is for illustration purpose. 
            // In short, Once you call the method ProcessShipment, it should process completely
            this.Agent = new InternationalAgent();
        }

        Console.WriteLine("Process international shipment for " + customerDetails.CustomerName + " and the agent is "
            + this.Agent.AgentName + " and dicount is " + this.Agent.Discount + "%");
    }
}

But, how is it useful? Say we need to process the shipment based on the selection of shipment type, then this is going to be very useful.
e.g.
/// <summary>
/// Holds the object:
/// I am still confused, whether a dictionay
/// like this should be used to implement OCP.
/// </summary>
private static Dictionary<int, IShipment> shipments;

public SolidPrinciples()
{
    // All the shipments are added in the application.
    // This will be a change in the parent form; 
    // Can be considered as a minor change
    shipments = new Dictionary<int, IShipment>
        {
            { 0, new LocalShipment() }, 
            { 1, new InternationalShipment(null) }
        };

    Console.WriteLine("Press any key to continue...");
    Console.ReadKey();
    Console.WriteLine("Please select the shipment type");
    var key = Convert.ToString(Console.ReadKey().KeyChar);
    while (key != "3")
    {
        var shipmentId = Convert.ToInt32(key);
        Shipment(shipmentId);
        Console.WriteLine("Please select the shipment type");
        key = Convert.ToString(Console.ReadKey().KeyChar);
    }
}

private static void Shipment(int shipmentId)
{
    var shipment = shipments.FirstOrDefault(o => o.Key == shipmentId).Value;

    if (shipment != null)
    {
        shipment.ProcessShipment(new Customer(new SavingsAccount()));
    }
}

Hope Open Closed Principle is clear for you. The series is not yet finished.

References
Thanks for Joel Abrahamson for providing simple explanation in his blogGavrav Sharma’s example was very easy to understand for beginners. Thank you. GauravDerick Bailey’s article in his blog explained everything about SOLID. Thank you Derick

Comments