I Am Not Myself

Bills.Pay(Developer.Skills).ShouldBeTrue()

S.O.L.I.D. By Example: Open Closed Principal

I’ll be presenting on the topic of Dependency Injection at the South Sound .NET Users Group on February 12th, 2009. In an effort to beef up my presentation to close to two hours, I decided to give a brief introduction to the S.O.L.I.D. Principals as described by Uncle Bob Martin as supporting material/introduction to Inversion of Control and Dependency Injection.

You can find the the first post in this series here:

S.O.L.I.D. By Example: Single Responsibility Principal

The Single Responsibility Principal demonstrated how to keep classes simple, focused and uncluttered. The Open Closed Principal is about protecting behavior that we know works. OCP states:

You should be able to extend a classes behavior, without modifying it.

Let’s jump right into the example to demonstrate the difference. Imagine that we are given a specification for an order service that saves orders to a database. Our initial implementation might look something like this:

public class OrderService
{
  private readonly OrderRepository _orderRepository;
 

  public OrderService(OrderRepository orderRepository)
  {
    _orderRepository = orderRepository;
  }

  public bool SaveOrder(Order order)
  {
    if (order.IsValid)
    {
      _orderRepository.Save(order);
    }
    return true;
  }
}

We have a simple order service that verifies an order is valid and then saves it to an order repository. Pretty clean and it appears to conform with SRP. Good times!

Two months later we get an addendum to the specification that states the company would like the order service to also send a confirmation email out when the order is accepted and saved to the database.

No problem! We start hacking away and come up with version 2 of our class:

public class OrderService
{
  private readonly EmailService _emailService;
  private readonly OrderRepository _orderRepository;
 

  public OrderService(EmailService emailService, OrderRepository orderRepository)
  {
    _emailService = emailService;
    _orderRepository = orderRepository;
  }

  public bool SaveOrder(Order order)
  {
    if (order.IsValid)
    {
      _orderRepository.Save(order);
    }
    if (Configuration.SendEmailConfirmation)
    {
      _emailService.SendConfirmation(order);
    }
    return true;
  }
}

In our edits we have modified our order service and added a dependency on a new class called email service. We have also modified the save order method to use the new email service. We also added to the complexity of the class by adding additional branching logic in the body of the save order method.

So in essence we took a class that had been written, presumably tested and functioning fine for a couple months and modified its behavior potentially breaking not only the new specification but the original at the same time.

Instead, we could approach the problem a different way to preserve the working functionality of the order service class but add additional behavior to it by extending the class.

All we would need to do is modify the original class like this:

public class OrderService
  {
private readonly OrderRepository _orderRepository;
 

public OrderService(OrderRepository orderRepository)
{
  _orderRepository = orderRepository;
}

public virtual bool SaveOrder(Order order)
{
  if (order.IsValid)
  {
    _orderRepository.Save(order);
  }
  return true;
}

Note that the save order method has been marked as virtual. This allows us to provide an alternative implementation. You can look at this as opening the class up to extension of its behavior.

So to add the new specified behavior we simply inherit from order service and override the save order method like this:

public class EmailingOrderService : OrderService
  {
private readonly EmailService _emailService;
 

public EmailingOrderService(EmailService emailService, 
  OrderRepository orderRepository) 
  : base(orderRepository)
{
  _emailService = emailService;
}

public override bool SaveOrder(Order order)
{
  if (base.SaveOrder(order))
  {
    _emailService.SendConfirmation(order);
  }
  return true;
}

We create a new emailing order service that inherits from order service. The constructor has a dependency on the original order repository which it passes along to its base class. It also adds a new dependency on email service.

The new implementation of save order delegates the saving of the order to its base class and then uses the email service to send the email confirmation.

So we have effectively added the new behavior in such a way that we are not potentially breaking the original object. We have also prevented the addition of branching complexity and overall lines of code within the save order methods.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: