PHP 设计模式:私有构造函数是不是不利于您让其他人扩展的类?
Posted
技术标签:
【中文标题】PHP 设计模式:私有构造函数是不是不利于您让其他人扩展的类?【英文标题】:PHP Design Patterns: Are private constructors bad for classes that you will let others to extend?PHP 设计模式:私有构造函数是否不利于您让其他人扩展的类? 【发布时间】:2012-01-16 11:18:53 【问题描述】:我有一个名为 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
构造函数是公共的,用户可以这样做:
$page = new Page($valid_page_id);
并最终调用 ContentAbstract::__construct()
但无法初始化页面本身的数据(template_file
和 short_name
),因为它是在 Page::newFromName()
和 Page::newFromID()
之外调用的。所以我最终得到了一个半熟的内容数据。一种解决方案是用类似于Page::newFromID()
的东西覆盖父构造函数,确保我们能够在Page
被实例化时设置所有字段(当然仍然在Page::__construct()
中调用父构造函数)。
现在问题出在Page::newFromName()
方法上,因为这种方法需要我进行2次查询,一个是使用short_name
列获取页面的内容id,然后当页面的构造函数在Page::newFromName()
中调用,然后它将创建一个新查询来获取与页面关联的数据。这不是可取的,不是吗?
所以我看到的唯一解决方案是将Page::__construct()
设为私有并强制最终用户使用静态方法来实例化对象。
我的问题是,这是我想作为一个开源项目发布的东西,它允许用户通过简单地继承 ContentAbstract
类来添加更多类型的内容。是否要求私有构造函数不利于上述目标(考虑人为错误和懒惰阅读文档)?或者这些事情应该是我最不关心的事情?还是实际类的结构本身导致了这个问题?
【问题讨论】:
Ahhhh...但是我怎么知道构造函数是否是从类本身调用的呢? 我意识到我误读了您想要做的事情,因此我的建议被误导了——对于那个偏离主题的问题感到抱歉。为了不混淆任何人,我删除了我的 cmets! 【参考方案1】:“现在我的问题在于Page构造函数是公共的,用户可以这样做:
$page = new Page($valid_page_id);"
根据您在 OP 中发布的代码,情况并非如此。您的页面扩展了构造所在的 ContentAbstract,但您实际上并未从 Page 类调用构造。您将不得不强制从孩子呼叫父母:
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);
【讨论】:
是的,问题是我从未重写父构造函数,所以Page
构造函数也是公共的。因此,只要我在new Page($id)
中传递一个有效的ID,脚本就不会抱怨。但是,由于 Page 的所有属性的初始化都是在静态方法中完成的,因此只有继承的属性会这样设置。
@RolandoCruz:当然。当我实现一个像你这样的结构时,我总是覆盖它。
@RolandoCruz:刚刚有了一个想法,为什么不将 ContentAbstract::__construct() 的内容移动到 protected init()
方法中。这样在实例化的时候不能直接访问代码,而你的静态方法仍然可以初始化成员变量?
@RolandoCruz:你最终做了什么来解决你的问题?以上是关于PHP 设计模式:私有构造函数是不是不利于您让其他人扩展的类?的主要内容,如果未能解决你的问题,请参考以下文章