重写工厂方法:如何返回子类对象类型


Overriding of factory methods: how to return the child class object type?

假设我在PHP中有一个父类,如下所示:

class A {
    private $property;
    public static function factory($arg) {
        $object = new A();
        $object->property = $arg;
        return $object;
    }
}

我想以这种方式扩展它:

class B extends A {
    public static function factory() {
        return parent::factory('constant');
    }
}

当我这样做B::factory()时,我得到一个类型为 A 的对象。如果我想要一个类型为 B 的对象怎么办?我无法更改类 A 代码中的任何内容

第一个版本

这是因为您在工厂方法中对 A 类进行了硬编码。
在类 A 中,而不是尝试$object = new A()(需要 Php 5.3(:

$class_name = get_called_class();
$object = new $class_name;

get_called_class()"获取调用静态方法的类的名称"。

较短的版本:

$object = new static();

第 2 版(硬编码父类(:

手动复制对象属性:

$parent = parent::factory($args);
$obj = new static();
$obj->setTimestamp($parent->getTimestamp());
$obj->setTimezone($parent->getTimezone());
return $obj;

或者使用黑客自动完成:

如何在 PHP 中强制转换对象

在您的示例中:

  1. 您有两个类(至少(
  2. 这两个类都可以实例化(具体,不是纯类或抽象类(
  3. 一个类是另一个类的超类
  4. 这两个类都使用"工厂"方法实例化
  5. 子类的"工厂"方法
  6. 可以调用超类的"工厂"方法
  7. 每个"工厂"方法可以有多种类型或参数计数

问题

现在,这就是它引起我注意的:

class B extends A {
    public static function factory() {
        return parent::factory('constant');
    }
}

简短和快速回答:

将其更改为:

class B extends A {
    public static function factory() {
        return A::factory('constant');
    }
}

长无聊的时髦扩展答案:

您正在尝试覆盖(并使用不同的参数重载(静态函数。

这是一个常见的错误,它假设静态方法是虚拟的,并且可以被覆盖。一些编程语言允许(Object Pascal,Delphi(,其他则不允许(C#,Java(,我认为PHP取决于版本。

老实说,"静态函数"的工作方式类似于具有命名空间的全局函数,它们对类的所有成员具有公共访问权限,而不是方法。我建议始终将它们视为全局函数。

干杯。