设计模式——反模式调用超级避免或保留


Design patterns - anti pattern call super - avoid or keep

我最近注意到,在某些情况下我真正喜欢做的事情(调用super)是一个反模式。(http://en.wikipedia.org/wiki/Call_super)

我的问题是:

如何做以下事情(我们大多数人都需要的基本事情,为对象添加一些细节)。我将在对象var:

中为数组添加一个新元素
   <?php
   class A {
       // bla bla bla
       public function __construct() {
            $this->_data['newDetail'] = "Ipiicaei";
       }
   }

   class B extends A {
       // bla bla bla
       // Override constructor, I need to add one more detail for this class
       public function __construct() {
            parent::__construct();
            $this->_data['newDetailSubcls'] = "Something";
       }
   }

现在…如果我不调用父类构造函数来添加第一个元素,我有两种可能:

  1. 在每个子类中添加父类通常执行的部分代码,并将其从父类中删除。因此,如果我用999个类扩展它,我将在parent中复制999*行。

  2. 从父类调用在子类中实现的方法(模板方法模式,他们推荐的)。因此,如果我只需要一个类来添加它,并且998的其余部分的行为与父类完全相同,则在每个类中添加一个空函数。

请记住,我的例子是简单的(这是一个例子应该如何),但父类和/或子类可能会做复杂的事情。

我可以理解为什么在某些情况下调用super可能是不好的。但我觉得这个还行。

所以…你会怎么接近?忽略call super是一个反模式,并按照我的做法(或者如果我的方式不好,过去会这样做)?还是……如何?

使用构造函数是这种反模式出现的一个不好的例子,因为在PHP中,就像在大多数支持继承的语言中一样,

如果子类没有定义构造函数,那么它可以像普通的类方法一样从父类继承…(来自PHP手册).

如果在您试图定义的其他998个类中的任何一个中故意不包含构造函数,则基构造函数将被调用,这几乎要求在每个派生类上添加构造函数以避免此功能。这就是为什么不建议在构造函数中添加可能改变受保护字段/属性状态的逻辑,或者调用可能在派生类中被覆盖的虚方法。

然而,反模式实际上表示:

请注意,调用父元素的要求是反模式(来自维基百科)

所以,调用方法的基类版本是可以的,只要派生类不要求调用方法的基类版本。派生类必须行为正确,即使基方法从未被调用。这将避免这样一种情况:派生类覆盖了虚拟方法,但没有实现某些特殊要求(可能是因为缺乏基类的文档),此时派生类的行为不符合系统的预期,可能导致系统崩溃或意外行为,这是典型的违反Liskov替代原则的情况。

在您的特定示例中,此反模式不适用:您正在扩展构造函数,根据定义,当它们将类实例化为有用状态时需要调用构造函数。在大多数情况下,这就是你想要的。