jjzjj

PHP 设计模式 : Are private constructors bad for classes that you will let others to extend?

coder 2024-04-22 原文

我有一个名为 ContentAbstract 的抽象类,它看起来像这样

abstract class ContentAbstract
{
  protected static $type;
  protected $id;
  protected $title;
  protected $description;

  protected $page;
  protected $section;
  ...

  function __construct($id = NULL, Page $page = NULL, Section $section = NULL)
  {
    if($id != NULL)
    {
      $data = get_data_from_content_table_by_id($id);

      if($data['type'] == static::$type)
      {
        initialize_fields_with_data($data);

        $this->page = fetch_page_object_from_registry($data['page_id']);
        $this->section = fetch_section_object_from_registry($data['section_id']);
      }
      else
        throw new IncompatibleContentTypeException('Foo');
    }
    else if($page != NULL && $section != NULL)
    {
      $this->page = $page;
      $this->section = $section;
    }
    else
      throw new OphanContentException('Foo');
  }
}

那么Page类也是ContentAbstract的子类

class Page extends ContentAbstract
{
  protected static $type = 'Page';

  private $template_file;
  private $short_name;

  static function newFromName($name)
  {
    $data = get_content_id_from_page_table_using_the_short_name($name);
    $page = new Page($data['id']);
    $page->template_file = $data['template_file'];
    ...
  }

  static function newFromID($id)
  {
    $data = get_content_id_from_page_table_using_the_ID($id);
    $page = new Page($data['id']);
    $page->template_file = $data['template_file'];
    ...
  }
}

现在我的问题在于 Page 构造函数是公共(public)的,用户可以这样做:

$page = new Page($valid_page_id);

并最终调用 ContentAbstract::__construct() 但无法初始化页面本身的数据(template_fileshort_name) 因为它是在 Page::newFromName()Page::newFromID() 之外调用的。所以我最终得到了一个半生不熟的内容数据。一种解决方案是使用类似于 Page::newFromID() 的方法覆盖父构造函数,确保我们能够在实例化 Page 时设置所有字段(当然,仍然通过在 Page::__construct()) 中调用父构造函数。

现在问题出在 Page::newFromName() 方法中,因为这种方法需要我进行 2 个查询,一个是使用 获取页面的内容 ID short_name 列,然后当在 Page::newFromName() 中调用页面构造函数时,它将创建一个新查询以获取与页面关联的数据。这是不可取的,不是吗?

所以我看到的唯一解决方案是将 Page::__construct() 设为私有(private)并强制最终用户使用静态方法来实例化对象。

我的问题是,这是我想作为开源项目发布的东西,它允许用户通过简单地子类化 ContentAbstract 类来添加更多类型的内容。要求私有(private)构造函数是否不利于上述目标(考虑到人为错误和懒惰阅读文档)?或者这些事情应该是我最不关心的?还是实际类的结构本身导致了这个问题?

最佳答案

“现在我的问题在于 Page 构造函数是公共(public)的,用户可以这样做:

$page = new Page($valid_page_id);"

根据您在 OP 中发布的代码,情况并非如此。您的页面在构造所在的位置扩展了 ContentAbstract,但您实际上并没有从 Page 类调用构造。您将不得不强制 child 给 parent 打电话:

class Page extends Content // I wouldn't name this abstract as it may change in the future
{
    public function __construct($args)
    {
        // Here I forced a call to parent
        // If I comment this out, the parent construct will never be accessed
        parent::__construct($args); 
    }
}

关于PHP 设计模式 : Are private constructors bad for classes that you will let others to extend?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8440848/

有关PHP 设计模式 : Are private constructors bad for classes that you will let others to extend?的更多相关文章

随机推荐