The Interface Segregation Principle (ISP)
“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
SPLIT library has MPROPS interface, but no GETFRG, LOAD1, GETCNAME
UNISIM Extension interface
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.