设计模式实例讲解 - 接口隔离
说明
接口隔离原则的通俗描述如下
客户端不应当被迫实现它不需要用到的接口
不好的示例
工人包括工作和睡觉两种行为
class Worker {
public function work()
{
}
public function sleep()
{
}
}
机长则负责管理生产,需要管理生产要素
class Captain {
public function manage(Worker $worker)
{
$worker->work();
$worker->sleep();
}
}
但是生产要素不仅仅包括工人,机器也算。通常,我们会约定好「生产要素」
interface WorkerInterface {
public function work();
public function sleep();
}
再分别定义人和机器
class HumanWorker implements WorkerInterface {
public function work()
{
return 'human working'
}
public function sleep()
{
return 'human sleeping';
}
}
class AndroidWorker implements WorkerInterface {
public function work()
{
return 'Android working';
}
public function sleep()
{
return null;
}
}
现在,问题来了。机器没有 sleep
这个行为,却被迫去实现该接口。这明显违反了接口隔离原则。
改进 1
首先,我们想到以将「工作」和「睡觉」两个行为分别隔离出来
工作接口
interface WorkableInterface
{
public function work();
}
睡觉接口
interface SleepableInterface
{
public function sleep();
}
工人和机器根据自身情况去实现这些接口
class HumanWorker implements WorkableInterface, SleepableInterface
{
public function work()
{
return 'human working.';
}
public function sleep()
{
return 'human sleeping';
}
}
class AndroidWorker implements WorkableInterface
{
public function work()
{
return 'android working.';
}
public function beManaged()
{
$this->work();
}
}
机长
class Captain
{
public function manage($worker)
{
if($worker instanceof WorkableInterface){
$worker->work();
} else if($worker instanceof SleepableInterface){
$worker->sleep();
}
}
}
虽然我们分离了工作和睡觉两个行为,避免了违反接口隔离原则。但是该例子仍然有问题,我们可以看出, Caption
类对 manage
是开放的,一旦添加新的生产要素,就必须去修改该代码,很明显,违背了开放封闭原则。
最终改进
Captain
的变化的行为为 manage
,将其分离出来
interface WorkableInterface
{
public function work();
}
interface ManageableInterface
{
public function beManaged();
}
对应的生产要素分别实现相应的接口
class HumanWorker implements WorkableInterface, SleepableInterface, ManageableInterface
{
public function work()
{
return 'human working.';
}
public function sleep()
{
return 'human sleeping';
}
public function beManaged()
{
$this->work();
$this->sleep();
}
}
class AndroidWorker implements WorkableInterface, ManageableInterface
{
public function work()
{
return 'android working.';
}
public function beManaged()
{
$this->work();
}
}
保持 Captain
类的封闭性
class Captain
{
public function manage(ManageableInterface $worker)
{
$worker->beManaged();
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接