PHP Course : SOLID - Interface Segregation
"Interface Segregation"... what the hell does that mean now... It seems like all those principles were named to bring more confusion than clarity right ? Yet they are very easy to understand once you look at the right example.
This one in particular sounds confusing but is fairly easy to understand. Let's dive right in.
This principle states that a client should not be forced to implement an interface that it doesn't use.
Can't really make it easier than that.
Like all the other principles, it all comes back to the idea of knowledge. The knowledge that an object has of another object.
Imagine this simple code: A ProjectManager
object that can manage()
a Developer
class ProjectManager
{
public function manage(Developer $developer)
{
$developer->code();
$developer->test();
}
}
class Developer
{
public function code()
{
// code...
}
public function test()
{
// code...
}
}
Here, ProjectManager
has knowledge of Developer
, meaning that ProjectManager
depends on Developer
. And if ProjectManager depends on Developer, then ProjectManager depends on whatever Developer depends as well.
As you can imagine, that may not be ideal. There is too much shared knowledge here.
Now what if the ProjectManager hires a Tester
? A Tester doesn't code()
and yet they are required to deliver the project.
Yeah, we know what to do, right ? We just need to setup an interface!
interface WorkerInterface
{
public function code();
public function test();
}
class Developer implements WorkerInterface
{
public function code()
{
return 'coding';
}
public function test()
{
return 'basic testing';
}
}
class Tester implements WorkerInterface
{
public function code()
{
return null;
}
public function test()
{
return 'advanced testing';
}
}
But mmmh, this looks weird doesn't it ? A Tester
doesn't code, so we have to return null
. And this is bad.
Well this is what Interface Segregation is all about.
Client should not be forced to implement interface they don't use. And right now, Tester
is being forced to implement the code
method even though there is no use for it. This violates the Interface Segregation Principle.
How can we solve that? We see that the issue comes from the WorkerInterface
which force its subclasses to implements both methods.
The solution is quite easy, we just need to split this interface into smaller chunks. Even an interface with a single method is perfectly fine. You should worry about interface that are too big (fat interfaces), not too small.
By splitting up the WorkerInterface
we have something like this:
interface CodeableInterface
{
public function code();
}
interface TestableInterface
{
public function test();
}
class Developer implements CodeableInterface, TestableInterface
{
public function code()
{
return 'coding';
}
public function test()
{
return 'basic testing';
}
}
class Tester implements TestableInterface
{
public function test()
{
return 'advanced testing';
}
}
But what about the ProjectManager
class then?? This one is not interested anymore in Developer or Tester, but only in CodeableInterface and TestableInterface, right?
class ProjectManager
{
public function manage(TestableInterface $worker)
{
if ($worker instanceof Developer) { // breaks the Open-Closed Principle!
$worker->code();
}
$worker->test();
}
}
This problem sounds familiar ? This is because we discussed it in the Open-Closed Principle.
If you remember correctly this lesson, you should know how to fix this problem.
We need another Interface! Yes, because the ProjectManager doesn't need to know if the worker is a Tester
or a Developer
(at least in this example), he just wants to have to work done! He's only interested in Managable
classes... See where this is going ? π
class ProjectManager
{
public function manage(ManagableInterface $worker)
{
$worker->work();
}
}
interface ManagableInterface
{
public function work();
}
interface CodeableInterface
{
public function code();
}
interface TestableInterface
{
public function test();
}
class Developer implements CodeableInterface, TestableInterface, ManagableInterface
{
public function work()
{
$this->code();
$this->test();
}
public function code()
{
return 'coding';
}
public function test()
{
return 'basic testing';
}
}
class Tester implements TestableInterface, ManagableInterface
{
public function work()
{
$this->test();
}
public function test()
{
return 'advanced testing';
}
}
Hopefully, this makes sense π
See how everything is cleaner ? No conditions whatsoever.
I'm just going to repeat myself, but with the above example it should be cristal clear:
A client should not be forced to implement an interface that it doesn't use.
I consider myself as an IT Business Artisan. Or Consultant CTO. I'm a self-taught Web Developper, coach and teacher. My main work is helping and guiding digital startups.
more about meBTC
18SY81ejLGFuJ9KMWQu5zPrDGuR5rDiauM
ETH
0x519e0eaa9bc83018bb306880548b79fc0794cd08
XMR
895bSneY4eoZjsr2hN2CAALkUrMExHEV5Pbg8TJb6ejnMLN7js1gLAXQySqbSbfzjWHQpQhQpvFtojbkdZQZmM9qCFz7BXU
2024 © My Dynamic Production SRL All rights Reserved.