Interface Segregation Principle (ISP)
The Interface Segregation Principle says that no code should depend on methods that it doesn’t use.
Core ideas:
- We prefer many small interfaces over one larger, more complicated interface
- If a class has many functionalities, each client of the class should only see the functionality that it needs
Example
Example: Video Game (No NVI for simplicity)
class Enemy {
public:
virtual void strike(); // Used in the combat process
virtual void draw(); // Used by UI of our game
} ;
class UI {
vector<Enemy*> enemies; // All the enemeis the UI might need to draw
};
class Battlefield {
vector<Enemy*> enemies; // All the enemies that might perform combat
};
Imagine we make a change to our drawing interface
battlefield.cc
must still recompile, even though it’s not using any part of the drawing interface- Needless Coupling between
UI
andBattlefield
viaEnemy
One solution: Multiple Inheritance
class Enemy: public Draw, public Combat {};
class Draw {
public:
virtual void draw() = 0;
};
class Combat {
public:
virtual void strike() = 0;
};
class UI {
vector<Draw*> enemies;
}
class Battefield {
vector<Combat*> enemies;
}
Somewhat similar to the Adapter Pattern - used when a class provides an interface different from the one you need.
For example - Library
for our window - expects objects to inherit from “Renderable” and provide a “render” method.
Don’t want to change all of our inheritance hierarchy, or all our draw calls to render - violates open / closed, pain. Use an adapter class.
- Satisfy the
Renderable
interface by calling the methods we’ve already defined. - We might not even need our Adapter to provide this “draw” method anymore, just render. In which case, we could use Private Inheritance.
Protected and private inheritance are not is-a (Specialization) relationship.
As such, we cannot use classes with private or protected inheritance polymorphically.
A* p = new B{...}; // only legal under public inheritance
Multiple inheritance can have some tricky semantics.
class A1 {
public:
void foo() {cout << "A1::foo" << endl;};
};
class A2 {
public:
void foo() {cout << "A2::foo" << endl;};
}
class B: public A1, public A2 {}
B b{};
b.foo(); //what should happen?
Ambiguous - it’s not clear whether A1::foo
or A2::foo
should be called - b.foo()
doesn’t compile. Disambiguate: b.A1::foo()
or b.A2::foo()
Question
Can you do this if
b
inherits from a single class, sayclass B: public A
, can you doB.A::foo()
?Although not needed, yes you can do this! It’s using the Scope Resolution Operator.
Another tricky aspect of multiple inheritance - shared base class. ”Diamond Problem”, “deadly diamond of death”.