我有一些处理程序(“控制器”)类,他们可以以某种方式处理项目:
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(); } }
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等其他类型的语言中,您的实现绝对合法.
原文链接:https://www.f2er.com/php/134144.html在对你的问题进行一些思考之后,我找到了Félix提出的解决方案,但是我认为与问题相比它的设计太多了.
我对你的问题的回答不是解决方案,而是我在用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; } }
我希望能帮到你. ^ _ ^