SOLID OOP Development: Interface Segregation Principle
As we make our way through the SOLID Development journey, it’s time we turned to the I in SOLID, which represents the: interface segregation principle.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

As we make our way through the SOLID Development journey, it’s time we turned to the I in SOLID, which represents the: interface segregation principle.

large

Interface Segregation Principle Definition

As with several of the other SOLID design concepts, this represents a scary name for an important topic. A dead simple definition of the interface segregation principle is that code should not be forced to depend on methods that it doesn’t use.

If this is a bit fuzzy, don’t worry I’m going to walk through a code example that clears it up.

Believe it or not, this is one of the easier SOLID concepts to understand and work with.

Interface Segregation Principle Code Example

Let’s start by taking a look at a program that manages a blog.

class Blog
  def edit_post
    puts "Post edited"
  end

  def delete_post
    puts "Post removed"
  end

  def create_post
    puts "Post created"
  end
end

blog = Blog.new
blog.edit_post
blog.delete_post
blog.create_post

(Obviously this program simply prints out some values in each method). If we run the program you’ll see that this code works properly.

Post edited
Post removed
Post created

Introducing the Moderator

Now what happens if we want to create a Moderator class? On a side note: let’s ignore the fact that a Moderator class should never be connected or inherit from a Blog class since a moderator isn’t a type of blog. However in preparing for this guide I walked through a number of examples and this case study illustrated the interface segregation principle the best.

Our Moderator class is very specialized. Moderators should only be able to edit a post. However this poses a problem because if we try to use code like this:

class Blog
  def edit_post
    puts "Post edited"
  end

  def delete_post
    puts "Post removed"
  end

  def create_post
    puts "Post created"
  end
end

class Moderator < Blog
end

moderator = Moderator.new
moderator.edit_post
moderator.delete_post
moderator.create_post

The problem with this Moderator class is that it not only can edit posts, but also delete posts. For practical reasons this is bad. However it is also breaking the interface segregation principle because we’ve intertwined our Blog class with our Moderator. And even though Moderator may not directly depend on all of the Blog methods, it’s still coupled with them since they can be called from instances of the class.

A Better Way

Thankfully Ruby offers us a better way of giving us the behavior that we need. By leveraging the Forwardable module we can limit the scope of what our Moderator class can access.

require 'forwardable'

class Blog
  def edit_post
    puts "Post edited"
  end

  def delete_post
    puts "Post removed"
  end

  def create_post
    puts "Post created"
  end
end

class Moderator
  extend Forwardable
  def_delegators :@blog, :edit_post

  def initialize(blog)
    @blog = blog
  end
end

moderator = Moderator.new(Blog.new)
moderator.edit_post
moderator.delete_post

This code starts by importing the Forwardable module in both the file and inside the Moderator class. Next we update the Moderator class so it no longer inherits from Blog. With those components cleaned up we can leverage the Forwardable module’s def_delegators method to list what we want the Moderator class to have access to.

In this case we want the Moderator to have access to the Blog class and the edit_post method inside of Blog. Notice how this is different than having Moderator inherit from Blog? Instead of giving access to the full class definition we’re able to pick and choose what elements Moderator should be able to work with.

Next we’ll setup an initialize method that takes a blog as an argument. This is how we’re letting Ruby know that our Moderator class needs to be passed the Blog class as an argument.

Lastly we can instantiate a new Moderator and pass in a new Blog as an argument.

The Result

After running this code you’ll see that our moderator can edit posts successfully.

Post edited
solid.rb:28:in `<main>': undefined method `delete_post' for #<Moderator:0x007f7f5189a9e0 @blog=#<Blog:0x007f7f5189aa08>> (NoMethodError)

However when it tries to delete a post it gets an error since we didn’t give it access to that method.

A Caveat

Before ending this guide I want to make one point of clarification. The walk through I just went through is specific to how you can work with the interface segregation principle in the Ruby language. However, since Ruby is a dynamic language it doesn’t require developers to declare class and method types. The interface segregation principle has a number of other requirements for statically typed languages such as Java or c++. So please keep that in mind if you work with those types of languages.

Ruby does quite a bit of the hard work for us when it comes to Object Oriented Development, however this is still an important concept to understand. And as a bonus you were able to learn about the Forwardable module!