Open/Closed principle

We can detect the need to use this principle when a change in the module outcomes in a waterfall of changes that affect dependent modules. The design is said to be too inflexible.

The Open/Closed principle (OCP) advises us that we should refactor the application in a manner that future changes don't provoke further modifications.

The form to apply this principle correctly would be by extending the functionality with new code (for instance, using polymorphism) and never changing the old code, which is working already. We can find several strategies to achieve this goal.

Observe that closed for modification is especially meaningful when you have distinct, separate modules (DLLs, EXEs, and so on) that depend on the module to be changed.

On the other hand, using extension methods or polymorphic techniques allows us to perform changes in code without affecting the rest. Think, for example, about the extension methods available in the C# language since version 3.0. You can consider extension methods a special type of static method, with the difference that they are called as if they were instance methods of the extended type. You find a typical example in the LINQ standard query operators because they add a query functionality to the existing types, such as System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T>.

The classical and simplest example of this pattern is the client/server cohesion that is largely seen in development for many years. It is preferable that clients depend on servers' abstractions, not on their concretions.

This can be achieved with interfaces. Servers can implement a client interface that clients will use to connect to them. In this manner, servers can change without affecting the way clients use them (refer to the next diagram):

Open/Closed principle

Any subtype of client interface will be free to implement the interface in the way it deems more appropriate and as long as it doesn't break other clients' access.

Back to our sample

Now, let's imagine that the Mercedes corporation announces a change in their models, which allows you to receive a notification when the user is in danger due to the car approaching its speed limit.

On first view, some would think about modifying the Accelerate method to include an event that can communicate this circumstance to whatever user interface is using it.

However, that would violate the OCP, since the current version is already working properly. This is one case where polymorphism is useful.

We can create another overload of the Accelerate method to allow this. It could receive an argument (the brand) that identifies whether the call is being made from a Mercedes and launch an event call, so any client could act accordingly.

I'll duplicate the project in a new one with another name so that you always have distinct versions depending on the case (Demo2-OCP):

public virtual bool Accelerate(bool advise)
{
  bool speedExceeded = Speed + SpeedIncr > MaxSpeed;
  Speed = (speedExceeded) ? Speed : Speed + SpeedIncr;
  if (speedExceeded && advise && (SpeedLimit!= null))
  {
    SpeedLimit(this, newEventArgs());
  }
  return speedExceeded;
}
public event EventHandler SpeedLimit;

As you can see, we declare a new event member (SpeedLimit) and invoke the event if the Boolean value is true.

Since events are notifications and not direct function calls to the user interface, the UI is free to subscribe to the events required.

In the user interface, we should subscribe to the SpeedLimit event and modify our btnAccelerate_Click event handler in this manner to handle this situation:

private void btnAccelerate_Click(object sender, EventArgs e)
{
  if (theCar.Brand == "Mercedes")
  {
    theCar.Accelerate(true);
  }
  else { theCar.Accelerate(); }
  updateUI();
}

In the instantiation process, the subscription is quite simple, and we can also have the IDE to create the SpeedLimit event handler for us:

theCar.SpeedLimit += TheCar_SpeedLimit;
private void TheCar_SpeedLimit(object sender, EventArgs e)
{
  MessageBox.Show("Speed limit attempted");
}

Observe that I'm simplifying the code as much as possible because the interest here is showing coding practices that align with the SOLID principles.

When we execute this code, we can observe that—just for the Mercedes—if we try to pass the speed limit, a MessageBox popup indicating the circumstance appears (refer to the screenshot). The other brands are not affected:

Back to our sample

However, as we mentioned, the .NET framework also uses these patterns and others in different namespaces, and that also includes the important LSP principle, as we'll see next.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.76.204