【问题标题】:Static factory pattern with inheritance and type hints具有继承和类型提示的静态工厂模式
【发布时间】:2019-08-15 19:08:53
【问题描述】:

我正在尝试创建一个类 Developer,它是 Person 的子类。
我希望它们都使用静态工厂模式(或“命名构造函数”)。

我见过一些这种模式的例子,但没有一个使用继承。

问题 1
在示例中,它们使构造函数方法始终为私有。
是否可以对其进行保护以便从子构造函数中调用?
或者我应该解决使构造函数始终为私有的问题,并尝试从子级的 create 方法调用父级的 create 方法来构建继承?

问题 2
当我尝试实例化 Person 或 Developer 类时,出现以下错误。为什么?

PHP Fatal error:  Declaration of Developer::create(string $name, string $surname, ?int $yearsOfExperience = NULL, ?string $preferredLanguage = NULL): Developer must be compatible with Person::create(string $name, string $surname): Person in InheritanceTest.php on line 57

当我在create 方法中删除: self 类型提示时它可以工作,但我不明白为什么它们不兼容,如果DeveloperPerson 的子类。

提前致谢。

<?php

class Person
{
    protected $name;
    protected $surname;

    protected function __construct(string $name, string $surname)
    {
        $this->name = $name;
        $this->surname = $surname;
    }

    public static function create(string $name, string $surname): self
    {
        // Some validation

        if($name == ''){
            throw new InvalidArgumentException('A person name can not be empty.');
        }

        if($surname == ''){
            throw new InvalidArgumentException('A person surname can not be empty.');
        }

        return new self($name, $surname);
    }
}

class Developer extends Person
{
    protected $yearsOfExperience;
    protected $preferredLanguage;

    protected function __construct(string $name, string $surname, ?int $yearsOfExperience, ?string $preferredLanguage)
    {
        parent::__construct($name, $surname);

        $this->yearsOfExperience = $yearsOfExperience;
        $this->preferredLanguage = $preferredLanguage;
    }

    public static function create(string $name, string $surname, ?int $yearsOfExperience = null, ?string $preferredLanguage = null): self
    {
        // Some validation

        if($yearsOfExperience < 0){
            throw new InvalidArgumentException('The years of experience can not be negative.');
        }

        if($preferredLanguage == ''){
            throw new InvalidArgumentException('The preferred language can not be empty.');
        }

        return new self($name, $surname, $yearsOfExperience, $preferredLanguage);
    }
}

【问题讨论】:

  • Person::create():self 的返回类型(即返回类型 Person)!== Developer::create():self(返回类型开发人员)。 Developer::create() : Person { class code here } 应该可以正常工作。
  • @jibsteroos 是的,这会起作用,但是开发者的 create 方法旨在返回 Developer 的一个实例,覆盖 Person 的 create 方法。一种简单的方法是创建具有不同名称的方法,例如(createPerson、createDeveloper),但我认为我误解了这种模式的某些内容,必须有正确的方法来解决这个问题。
  • $dev = Developer::create('alex', 'pearson', 3, 'c++'); 然后var_dump($dev) 显示它是object(Developer)#2 (4) {...}
  • @jibsteroos 你是对的!我认为 PHP 应该认识到 Developer 扩展了 Person,并允许它作为 create 方法的返回提示。相反,当方法返回提示为Person 时,它返回一个Developer 实例,这对我来说毫无意义。感谢您的帮助!
  • 确实,很奇怪,不知道应该是这个样子,可能是bug……

标签: php inheritance type-hinting static-factory named-constructor


【解决方案1】:

问题 1:

在示例中,它们使构造函数方法始终为私有。 是否可以对其进行保护以便从子构造函数中调用?

您必须对其进行保护。否则不允许孩子调用父母的方法。

问题 2:

当我在两个 create 方法中删除 : self 类型提示时它会起作用,但如果 Developer 是 Person 的子类,我不明白为什么它们不兼容。

尝试使用static 而不是self。它可能有效,但我不确定。但是您仍然会注意到(或警告,不记得了),因为 Developer 中的工厂方法具有与 Person 不同的参数。在 PHP 中这是允许的,但不建议这样做。

【讨论】:

  • 错误标记的问题是Class Developer::create()中的返回类型声明必须与Person::create() : self声明的相同。在这种情况下,self 是 Person 类型的对象。因此,Developer::create() : Person { class code here } 应该可以正常工作。
  • 感谢您的回答。 Q1:我知道必须保护父级的构造函数才能从子级调用它。我的意思是:这是解决问题的正确方法(继承静态工厂)?使用构造函数构建继承?还是使用静态方法? Q2:我应该在哪里使用static而不是self?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多