SOLID Design Principles

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 and Battlefield via Enemy

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, say class B: public A, can you do B.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”.

Next