受保护的建设者是否被视为良好做法

时间:2010-06-08 09:55:25

标签: php oop

我正在编写一些小助手类来处理树木。基本上,我有一个节点和一个代表树的特殊根节点。我想保持它的通用性和简单性。这是代码的一部分:

<?php

class Tree extends TreeNode{
    public function addById($node_id, $parent_id, $generic_content){
        if( $parent = $this->findNodeById($parent_id) ){
            $parent->addChildById($node_id, $generic_content);
        }
    }
}

class TreeNode{
    public function __construct($node_id, $parent_id, $generic_content){
        // ...
    }

    protected function addChildById($node_id, $generic_content){
        $this->children[] = new TreeNode($this->node_id, $node_id, $generic_content);
    }
}

$Categories = new Tree;
$Categories->addById(1, NULL, $foo);
$Categories->addById(2, NULL, $bar);
$Categories->addById(3, 1, $gee);

?>

我的问题:

  • 通过TreeNode强制TreeNode::addById()个实例是否明智?
  • 如果是这样,将TreeNode::__construct()声明为私人/受保护是不错的做法?

2 个答案:

答案 0 :(得分:3)

我认为在某些情况下控制对象的构造并隐藏公共构造函数是有意义的。

对于您的代码也是如此:Tree类控制如何创建和初始化子TreeNode是有用的,因为它需要控制在树层次结构中添加节点的位置。< / p>

如果类之间的关系使得对象具有关于另一个的信息,那么对对象构造进行这种控制尤为重要。

例如:如果您稍微更改了实现并允许Tree类管理树中所有节点的节点ID(您可以将它们存储在Tree类中的数组中)。在这种情况下,让Tree控制如何创建和初始化TreeNode并通过Tree类上的方法完成这一操作非常有意义。

答案 1 :(得分:1)

  
      
  • 通过TreeNode强制TreeNode::addById()个实例是否明智?
  •   
  • 如果是这样,将TreeNode::__construct()声明为私人/受保护是不错的做法?
  •   

如果您想强制通过TreeNode创建TreeNode::addById(),那么唯一明智的路径就是让TreeNode::__construct()成为私有或受保护的(两者都有效)在这种情况下,private可能会更好,因为它会强制子类使用::addChildById)。

关于强制通过TreeNode强制创建TreeNode::addById()实例是否合理:它是,替代方案是将TreeNode::addById()的逻辑转移到构造函数。虽然在这种情况下可行,但工厂方法通常更通用。

但是,请注意,因为它现在是,并且因为在PHP中不需要调用父构造函数,所以可以创建(子类型)通过创建TreeNode个对象来Tree个对象。您应该考虑向Tree添加私有构造函数以避免实例化。

更正:尽管在PHP中不需要调用父构造函数,但如果在子类中没有指定构造函数,则对父构造函数进行隐式调用也是如此。就像现在一样,PHP会尝试调用TreeNode的父构造函数,并在直接实例化Tree对象时失败。