PHP/OOP 方法覆盖 DRY 方式

标签 php oop

我很好奇是否有针对以下行为的“更好”设计:

<?php
class Foo {
    public function foo() {
        // Foo-specific foo stuff.
    }
}

class Bar extends Foo {
    public function foo() {
        // Bar-specific foo stuff.
        parent::foo();
    }
}

class Baz extends Bar {
    public function foo() {
        // Baz-specific foo stuff.
        parent::foo();
    }
}

$boz = new Foo();
$boz->foo(); // should do the stuff in Foo::foo()

$biz = new Bar();
$biz->foo(); // should do the stuff in Bar::foo() and Foo::foo()

$buz = new Baz();
$buz->foo(); // should do the stuff in Baz::foo(), Bar::foo(), and Foo::foo()

// etc...

本质上,我有一个基类 Foo,它有一个方法 Foo::foo(),其中包含一些应该始终运行的通用代码。我还有各种继承自 Foo 的子类,每个子类都有自己的特定代码,这些代码也应该始终运行。

我在这里使用的设计使用 DRY 原则来确保 Foo::foo() 中的代码不会在 Bar::foo() 中重复> 和 Baz::foo()Bar::foo() 中的代码在 Baz::foo() 中没有重复> 等等。

这种设计的问题(?)是我依赖于子类在每种情况下总是显式调用 parent::foo(),以及扩展这些类的类来执行同理,以此类推。但是,(据我所知)没有办法实际执行此操作。

所以我的问题是 - 是否有更好的设计来实现相同的行为,或者是否有某种方式在父类/子类之间强制执行这种“契约”?

更新

有些人要求提供用例。多年来我在几个项目中遇到过这种范例,但由于 NDA 等原因无法给出真实世界的例子,所以这里有一个 super 基本的例子,可能有助于更好地说明这个问题:

<?php
// Vehicle
class Vehicle {
    public function start() {
        // Vehicle engines are on when you start them.
        // Unless they belong to me, that is :-(
        $this->setEngineStatus(Vehicle::ENGINE_ON);
    }
}

// Vehicle > Automobile
class Automobile extends Vehicle {
    public function start() {
        // Automobile engines are on when you start them.
        parent::start();

        // Automobiles idle when you start them.
        $this->setEngineRpm(Automobile::RPM_IDLE);
    }
}

// Vehicle > Airplane
class Airplane extends Vehicle {
    public function start() {
        // Airplane engines are on when you start them.
        parent::start();

        // Airplanes also have radios that need to be turned on when started.
        $this->setRadioStatus(Airplane::RADIO_ON);
    }
}

// Vehicle > Automobile > Car
class Car extends Automobile {
    public function start() {
        // Cars engines are on and idle when you start them.
        parent::start();

        // Cars also have dashboard lights that turn on when started.
        $this->setDashLightsStatus(Car::DASH_LIGHTS_ON);
    }
}

// Vehicle > Airplane > Jet
class Jet extends Airplane {
    public function start() {
        // Jet engines and radios are on when you start them.
        parent::start();

        // Jets also arm their weapons when started.
        $this->setWeaponsHot(true);
    }
}

// Vehicle > Automobile > BobsSuperAwesomeCustomTruck
class BobsSuperAwesomeCustomTruck extends Automobile {
    public function start() {
        // Uh-oh... Bob didn't call parent::start() in his class, so his trucks
        // don't work, with no errors or exceptions to help him figure out why.

        // Bob's trucks also need to reset their pinball machine highscores when started.
        $this->resetPinballScores();
    }
}

最佳答案

我不认为这更好,但这是一种可能的方式。

class abstract Foo {
    public function foo() {
        // Foo-specific foo stuff.
        $this->_foo();
    }

    // Might be abstract, might be an empty implementation
    protected abstract function _foo();
}

class Bar extends Foo {
    protected function _foo() {
        // Bar-specific foo stuff.
    }
}

就个人而言,我更喜欢你的方式,因为我认为它更具可读性。这也意味着 child 不必拥有自己的 foo() 实现。似乎更面向对象。但是,如果您需要每个子类都有自己添加的 foo() 实现,这可能会为您解决问题。

关于PHP/OOP 方法覆盖 DRY 方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7394986/

相关文章:

javascript - php ajax表单动态提交

java - 多态性是继承的迫在眉睫的副作用吗?

oop - 与 OOP 中的 'Ancestor' 相反

java - 更改 javafx 对象属性

php - Codeigniter:查询未正确打印

javascript - Jquery 未在 Wordpress 主题中正确排队

php - 试图从秒转换为日期

php 无法通过查询创建新的数据库表

c# - 重构 Java 周期性任务

c++ - 非成员函数如何实现类的友元函数的功能?