我有一种情况,即尽管有相当多的谷歌搜索/搜索,似乎逃脱了我。简而言之,这就是问题所在:
PHP 5.3+(但尚未具体 - 我实际上运行的是5.5 / 6,但环境的目标是灵活)。
我试图编写一个可以迫使其他开发人员进行最佳实践的可靠实现。
我有一个父类:
class A {
public function doSomething() {
// does something
}
}
标准用例是使用A::doSomething
。
在特殊情况下,需要扩展名。
class B extends A {
public function doSomething() {
// does something .. AND
$this->doSomethingElse()
}
private function doSomethingElse() {
// does something else
}
}
如果我想做某事,那么我可以A::doSomething
如果我想做某事并做其他事情,那么我可以B::doSomething
。
为了使让其他开发人员适应最佳实践,我已经实现了一个接口:
interface C {
public function doSomething() {
// does something else
}
public function doSomethingElse() {
// does something else
}
}
B类然后实现接口C.听起来很简单?
class B implements C {
public function doSomething() {
// does something .. AND
$this->doSomethingElse()
}
private function doSomethingElse() {
// does something else
}
}
我不想假设孩子B
实施C
将A
扩展到E
可能有一些完全正当的理由,其中E
不想实施C
。
如果我执行以下操作,并且未实施doSomething
方法,则以下内容没有错误:
class B implements C {
private function doSomethingElse() {
// does something else
}
}
..正如你所期望的那样; A
为doSomething
提供了B
来满足C
的要求。
问题是这会让某人编写一个不能抛出错误的不完整方法。在上述情况下,B::doSomething
不会调用B::doSomethingElse
。
方法,接口(或类似技术)是否有可能要求子项在当前继承级别实现方法?
当然我可以写笔记,文档等......但界面的重点是让人们正确地做到这一点!
其他提出类似问题的人要么(有时可以理解)被误解或股票回答是"架构错了" ......我和#39 ; d喜欢挑战,如下例所示:
以下是真实世界项目的示例:
A可能有一个名为... A::attemptToBuy
的方法
C
会强制执行ID所需的方法。
Beer
和Vegetable
都是ShopItem的类型
这是标准的逻辑继承。
Beer
需要使用BoozeInterface
(或任何合适的内容)。对于Wine
,Spirit
等尚未实施但未来可能的要求也是如此。
某些项目完全适合通用ShopItem
类。他们不需要额外的功能。
ShopItem::attemptToBuy
是一个正常的用例。
然而 - 我必须依赖有人记得覆盖Wine::attemptToBuy
和Spirit::attemptToBuy
。
正如您所看到的 - 如果我想真的将其锁定,我理想情况下可以强制覆盖当前的继承级别。
(我确定有更好的例子,但我已尽力使其尽可能明显。)
我很高兴,如果答案是"不,你不能这样做" ...我只是想知道你是否可以。我有代码工作,但只是通过非强制的直接覆盖。但我希望它被迫!
提前致谢。 瑞克
答案 0 :(得分:1)
为什么不将A类抽象化并以这种方式使用这些方法:
abstract class A
{
abstract protected function doSomething() {}
abstract protected function doSomethingElse() {}
}
现在任何扩展A类的类都必须定义这两个方法。
干杯!
答案 1 :(得分:0)
我认为您正在倒退 - 我不确定您是否希望在客户端 - 开发人员创建的子类中强制执行覆盖(使用抽象方法轻松完成),您希望提供在您提供的抽象类中重写不能的方法,以确保它能达到您想要的效果?
如果您提供抽象类ShopItem
和BoozeItem
,那么:
<?php
// base ShopItem with default `attemptToBuy` functionality
abstract class ShopItem {
public function attemptToBuy() {
echo "buying ShopItem";
}
}
// Booze sub-class, with an override on `attemptToBuy`
// (e.g. applying age restrictions check)
abstract class BoozeItem extends ShopItem {
final public function attemptToBuy() {
echo "buying BoozeItem";
}
}
?>
客户端开发人员可以愉快地创建扩展Beer
子类的BoozeItem
类。
<?php
class Beer extends BoozeItem { }
$oBevvy = new Beer();
$oBevvy->attemptToBuy();
?>
输出:购买BoozeItem
由于BoozeItem::attemptToBuy()
已声明为final
,因此无法被Booze::attemptToBuy()
覆盖(尝试创建该方法会导致错误) - 因此您的对象功能已被锁定
Beer
可以扩展到Lager
或Ale
(例如),这些会从attemptToBuy()
继承BoozeItem
(因为Beer
延伸BoozeItem
)但他们不会被允许覆盖该方法,因为它已声明final
- 它只是被定义的继承行为。这不是你想要的,但它可能是我认为最接近的。