设计模式实例讲解 - 接口隔离

说明

接口隔离原则的通俗描述如下

客户端不应当被迫实现它不需要用到的接口

不好的示例

工人包括工作和睡觉两种行为

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 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!