【问题标题】:Show warning when overriding method覆盖方法时显示警告
【发布时间】:2014-01-16 08:53:34
【问题描述】:

我有一些带有 foo 方法的抽象类 MyClass。当有人从此类继承并覆盖此方法时,从子类调用此方法很重要。所以我想在这种情况发生时发出警告。但是我不能修改子类,因为它不是我设计的。另外 foo 方法可以被覆盖但不是必须的。

在代码中,调用FirstClass::foo() 应该会导致警告,但SecondClass::foo() 不会。我该怎么做?

abstract class MyClass {
    public function foo() {
        // do something important
    }
}

class FirstClass extends MyClass {
    public function foo() {
        // do something special
    }
}

class SecondClass extends MyClass {
    public function foo() {
        parent::foo ();
        // do something special
    }
}

【问题讨论】:

  • 请显示警告信息,因为您当前的代码是正确的。
  • 这不是一种反模式,需要重写父方法吗? en.wikipedia.org/wiki/Call_super
  • 按常识 - 不。因为您无法从外部范围预测内部方法中发生的事情。如果是 设计您的子课程 - 那么为什么不添加直接检查呢?如果不是你 - 那么你应该添加一些有问题的限制
  • 我个人会为此使用接口。如果不应该调用来自FirstClassfoo,它不应该在类中。而SecondClass 可以实现需要这个方法的接口。

标签: php inheritance overriding


【解决方案1】:

你不能这样做。您可以在抽象类中添加一些标志并检查它,但这是错误的。

我建议你改用Template method pattern

abstract class MyClass {
    final public function foo() {
        // do something important
        $this->_overridableMethod();
    }

    abstract protected function _overridableMethod();
}

class FirstClass extends MyClass {
    protected function _overridableMethod(){
        // do something special
    }
}

【讨论】:

  • 不使用final可以做到吗?我们中的一些人遵循一切都应该是可扩展的理念。
  • @Flosculus,哲学呢:写代码没有警告?
  • 这是一个很好的解决方案。我没有考虑过这种设计模式。但是现在,子类必须实现_overridableMethod()。在我的情况下,某人不必实现 foo 方法,但如果他愿意,可以。
  • 但我可以在MyClass 中执行非抽象方法'_overridableMethod()'。现在它完美地工作了!谢谢。
  • @sectus 顺便说一句,您认为在这种情况下哪种解决方案更好:使用模板方法模式或为我的类编写文档,必须记住从基础调用 foo 方法上课?
【解决方案2】:

这是我如何做到这一点的骨架示例:

interface VehicleInterface
{
    public function move($x, $y);

    public function refuel($station);
}

interface FlyableInterface
{
    public function takeoff();

    public function land();
}

abstract class AbstractVehicle implements VehicleInterface
{
    /**
     * Implementation to refuel at station
     */
    public function refuel($station)
    {

    }
}

class Car extends AbstractVehicle
{
    /**
     * Implementation to move by following a road.
     */
    public function move($x, $y)
    {

    }
}

class Plane extends AbstractVehicle implements FlyableInterface
{
    /**
     * Implementation to move by means of flying.
     */
    public function move($x, $y)
    {

    }

    /**
     * Override of AbstractVehicle::refuel, landing required first.
     */
    public function refuel($station)
    {
        $this->land();
        parent::refuel($station);
    }

    /**
     * Implementation for plane to take off.
     */
    public function takeoff()
    {

    }

    /**
     * Implementation to land the plane.
     */
    public function land()
    {

    }
}

$vehicles = array(new Car(), new Plane());

$x = '145';
$y = '751';

foreach($vehicles as $vehicle) {

    if($vehicle instanceof FlyableInterface) {
        $vehicle->takeoff();
        $vehicle->move($x, $y);
        $vehicle->land();
    } else {
        $vehicle->move($x, $y);
    }
}

最后的执行脚本旨在根据每个类实现的方法不同地为每辆车执行相同的任务。飞机和汽车都实现了相同的move方法,并且都继承了相同的refuel方法,但是需要飞机先着陆。

执行脚本将通过检查它是否是特定接口的实例来检测支持的方法。

举个实际的例子,Symfony2 类Command 有一个名为ContainerAwareCommand 的变体。通过扩展它,框架知道注入服务容器,因为这样做的支持方法要么继承,要么由子类实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 2016-03-21
    • 2018-04-22
    • 2011-03-08
    • 2015-06-20
    • 1970-01-01
    相关资源
    最近更新 更多