php – Liskov替换原则和使用继承类的正确方法

前端之家收集整理的这篇文章主要介绍了php – Liskov替换原则和使用继承类的正确方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一些处理程序(“控制器”)类,他们可以以某种方式处理项目:
interface IHandler
{
    public function execute(Item $item);
}

class FirstHandler implements IHandler
{
    public function execute(Item $item) { echo $item->getTitle(); }
}

class SecondHandler implements IHandler
{
    public function execute(Item $item) { echo $item->getId() . $item->getTitle(); }
}

class Item
{
    public function getId() { return rand(); }
    public function getTitle() { return 'title at ' . time(); }
}

但是我需要在子Item类中添加一些新功能

class NewItem extends Item
{
    public function getAuthor() { return 'author ' . rand(); }
}

并在SecondHandler中使用它

class SecondHandler implements IHandler
{
    public function execute(Item $item) { printf('%d %s,author %s',$item->getId(),$item->getTitle(),$item->getAuthor()); }
}

但是Item类实际上没有getAuthor方法.并且,如果我尝试在SecondHandler类中更改accept方法的签名,我将捕获有关声明兼容性的E_STRICT错误.当然,这是一种LSP违规.

我该如何解决这个问题?我是否需要两个接口,例如,INewHandler和IHandler,具有不同的execute方法签名?但它是某种代码重复.

此外,我不能在处理程序中使用__constructor(Item $item)和__construct(NewItem $item)(以及不带参数的execute方法),这将被视为更好的解决方案:它们必须是不可变的,并且只允许每个策略的单个实例应用程序生命周期

正如您自己发现的那样,PHP的类型提示实现有很多限制,使得场景(如您所描述的场景)比它们应该更难.在Java和Swift等其他类型的语言中,您的实现绝对合法.

在对你的问题进行一些思考之后,我找到了Félix提出的解决方案,但是我认为与问题相比它的设计太多了.

我对你的问题的回答不是解决方案,而是我在用PHP开发多年后给你的建议:

放弃PHP中的类型提示,并以动态的方式开发它.

PHP比Java / C更类似于Ruby / Python / JavaScript,并且尝试从静态类型语言中复制1到1转换为强制和卷积实现.

解决您的实现问题很容易,所以不要过于复杂,并保持简单(KISS原则).

在没有类型的情况下声明方法的参数,并在您真正需要的地方实现检查(例如抛出异常).

interface IStrategy
{
    public function execute($item);
}

class FirstStrategy implements IStrategy
{
    public function execute($item) {
        echo $item->getTitle();
    }
}

class SecondStrategy implements IStrategy
{
    public function execute($item) {
        // execute(NewItem $item) is identical to this check.
        if (! $item instanceof NewItem) {
            throw new Exception('$item must be an instance of NewItem');
        }
        echo $item->getAuthor();
    }
}

class Item
{
    public function getId() { return rand(); }
    public function getTitle() { return 'title at ' . time(); }
}

class NewItem extends Item
{
    public function getAuthor() { return 'author ' . rand(); }
}

再一次,不要在Java中思考,而是尽可能地遵循鸭子打字的方式.

在可能的情况下,尽量不要严格强制参数的类型,而是根据可用的接口调整代码的行为(Duck Typing).

class SecondStrategy implements IStrategy
{
    public function execute($item) {
        $message = $item->getTitle();

        // PHP 5 interface availability check.
        if (is_callable([$item,'getAuthor'])) {
            $message .= ' ' . $item->getAuthor();
        }

        // With PHP 7 is even better.
        // try {
        //     $message .= ' ' . $item->getAuthor();
        // } catch (Error $e) {}

        echo $message;
    }
}

我希望能帮到你. ^ _ ^

原文链接:https://www.f2er.com/php/134144.html

猜你在找的PHP相关文章