我有一个情况,尽管有相当多的谷歌搜索/SO'ing,似乎逃脱了我。简而言之,这是问题所在:
情况
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
为B
提供了满足C
要求的doSomething
。
问题是这将允许某人编写一个不完整的方法,该方法将无法抛出错误。在上述情况下,B::doSomething
不会调用 B::doSomethingElse
。
、接口(或类似技术)是否有可能要求子级在当前继承级别实现方法?
当然,我可以写笔记,文档等......但界面的目的是让人们正确地做!
其他提出类似问题的人要么(有时可以理解)被误解,要么得到的答案是"架构是错误的"......我想挑战一下,如下例所示:
下面是真实世界物品的示例:
- A = 待售商店商品 : 商店商品
- B = 类型为"啤酒"的商店项目:啤酒
- C = BoozeInterface : .. 说触发 ID 要求的接口
- D = "蔬菜"类型的商店项目:蔬菜
A 可能有一个方法称为,例如... A::attemptToBuy
C
会强制执行诸如需要 ID 之类的方法。
Beer
和Vegetable
都是ShopItem的一种类型。
这是一个标准的逻辑继承。
Beer
需要使用BoozeInterface
(或任何合适的)。对于尚未实现的,但将来可能还需要Wine
、Spirit
等
有些项目非常适合通用ShopItem
类。它们不需要额外的功能。 ShopItem::attemptToBuy
是一个正常的用例。
但是 - 我必须依靠有人记住来覆盖Wine::attemptToBuy
和Spirit::attemptToBuy
.
如您所见 - 如果我想真正锁定它,理想情况下,我可以在当前的继承级别强制覆盖。
(我相信有更好的例子,但我试图让它尽可能明显)。
如果答案是"不,你不能那样做",我很高兴......我只想知道你能不能。我有代码工作,但只是通过非强制的直接覆盖。但我希望它是被迫的!
提前谢谢。瑞克
为什么不使类 A 抽象并以这种方式要求这些方法:
abstract class A
{
abstract protected function doSomething() {}
abstract protected function doSomethingElse() {}
}
现在,任何扩展类 A 的类都必须定义这两个方法。
干杯!
我认为您正在倒退 - 我不确定您是否要在客户端开发人员创建的子类中强制执行覆盖(使用抽象方法轻松完成),您想提供一个无法在您提供的抽象类中覆盖的方法以确保它执行您想要的功能?
如果提供抽象类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";
}
}
?>
然后,客户端开发人员可以愉快地创建扩展BoozeItem
子类的 Beer
类。
<?php
class Beer extends BoozeItem { }
$oBevvy = new Beer();
$oBevvy->attemptToBuy();
?>
输出:购买酒品
由于BoozeItem::attemptToBuy()
已被声明final
因此不能被Booze::attemptToBuy()
覆盖(尝试创建该方法将导致错误) - 因此您的对象功能被锁定。
Beer
可以扩展到Lager
或Ale
(例如),它们将从BoozeItem
继承attemptToBuy()
(因为Beer
扩展BoozeItem
),但它们不会被允许覆盖该方法,因为它被声明为final
- 它只会通过定义的行为继承。这不是你想要的,但我认为这可能是你最接近的。