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
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.
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
Post a Comment