The Interface Segregation Principle (ISP)

Alt text “CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE.” – Robert C. Martin

In the field of software engineering, the interface segregation principle (ISP) states that no code should be forced to depend on methods it does not use. ISP splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them. Such shrunken interfaces are also called role interfaces. ISP is intended to keep a system decoupled and thus easier to refactor, change, and redeploy. ISP violation is often root cause of LSP violation.

An short intro (10 min) into the topic is found here.

Bad Practice

struct FastFoodOrderService : public IOrderable {
    virtual void orderBurger(int quantity) = 0;
    virtual void orderFriedChicken(int quantity) = 0;
};
struct McDonalds : public FastFoodOrderService {
    void orderBurger(int quantity) override
    {
        std::cout << "Received order of " << quantity << " burgers";
    }
    void orderFriedChicken(int quantity) override
    {
        throw std::logic_error("We don't have Fried Chicken");
    }
};

Good Practice

struct IOrderable {
    virtual void order(std::list<std::string> ) = 0;
};
struct McDonaldsOrderService : public IOrderable {
    void orderBurger(int quantity)
    {
        order("order "s + std::to_string(quantity) + " burgers"s);
    }
};
struct KFCOrderService : public IOrderable {
    virtual void orderFriedChicken(int quantity) 
    {
        ...
    }
};

Examples at LE

Bad practice

Good practice

  • SimulationObject: One interface for flow sheets for all simulators

Code Smells for ISP Violations and How to Fix Them

Whether working solo or in larger teams, it helps to identify problems in code early. So, let’s discuss some code smells which could indicate a violation of the ISP.

A Bulky Interface

In bulky interfaces, there are too many operations, but for most objects, these operations are not used. The ISP tells us that we should need most or all methods of an interface, and in a bulky interface, we most commonly only need a few of them in each case. Also, when testing a bulky interface, we have to identify which dependencies to mock and potentially have a giant test setup.

Unused Dependencies

Another indication of an ISP violation is when we have to pass null or equivalent value into a method. In our example, we can use orderCombo() to place a burger-only order by passing zero as the fries parameter. This client does not require the fries dependency, so we should have a separate method in a different interface to order fries.

Methods Throwing Exceptions

As in our burger example, if we encounter an UnsupportedOperationException, a NotImplementedException, or similar exceptions, it smells like a design problem related to the ISP. It might be a good time to refactor these classes.

Alt text