gpt4 book ai didi

php - 里氏代换原则和继承类的正确使用方法

转载 作者:可可西里 更新时间:2023-11-01 12:57:34 24 4
gpt4 key购买 nike

我有一些处理程序(“ Controller ”)类,它们可以以某种方式处理项目:

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。

我该如何解决这个问题?我是否需要两个接口(interface),例如 INewHandlerIHandler,具有不同的 execute 方法签名?但这是某种代码重复。

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

最佳答案

正如您自己发现的那样,PHP 的类型提示实现有很多局限性,这些局限性使场景(如您描述的场景)变得比应有的更难。在 Java 和 Swift 等其他类型化语言中,您的实现是绝对合法的。

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

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

放弃 PHP 中的类型提示并按照它应该的方式开发......以动态方式

与 Java/C++ 相比,PHP 更类似于 Ruby/Python/JavaScript,并且试图从静态类型语言中一对一复制会导致强制和复杂的实现。

您的实现问题的解决方案很简单,所以不要过度复杂化并保持它应该的简单(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 方式。

如果可能,尽量不要严格强制参数的类型,而是根据可用接口(interface)(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;
}
}

希望对你有所帮助。 ^_^

关于php - 里氏代换原则和继承类的正确使用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34134270/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com