【问题标题】:OOP: hierarchical-dependency relation between objectsOOP:对象之间的层次依赖关系
【发布时间】:2014-04-07 11:15:42
【问题描述】:

对于一个项目,我正在解析和合并多个 xml 配置文件。这些 xml 配置定义了可能会或可能不会创建输出的块、在整个系统中可用的选项等。这些块是分层的,这意味着:一个块可以容纳其他块。

(合并的)配置可能如下所示:

<block name="root">

    <block name="sub">

        <block name="sub2">
            <option name="some-option" value="some-value" />
        </block>

        <option name="sub" value="value" />
    </block>

    <option name="key" value="value" />
    <remove name="sub" />
</block>

如您所见,块具有范围。这意味着:块sub 仅在块root 中可用,块sub2 仅在块sub 中可用。 但是:选项在任何地方都可用,但只有在包含块仍然存在时。如您所见,最后一行包含一个remove 'command',它从树中删除块sub,以及它的子块(块sub2 和选项some-optionsub)。

如何维护分层对象结构并保持对元素范围的引用?

我探索了一些选项,例如分层对象结构:

class Block {
    private $parent = null; // reference to parent block, or 'null' if no parent exists
    private $children = array(); // list of children blocks
    private $options = array(); // list of options
    private $removes = array(); // list of remove 'commands'
}

甚至是嵌套集模型(具有左右值的 sql 模式)。

但无论我尝试什么,仍然会出现一些问题:

  1. “暂存”:如何在“全局范围”中提供可用选项、删除等,但要跟踪它们的定义位置。例如:名称为“some-option”的选项应该可用于系统的任何部分,除非它包含的块(“sub2”)被删除。
  2. “堆叠”:我需要存储所有“删除”选项,直到整个 xml 树被解析,然后才应该执行所有删除。移除应该从外到内执行。这意味着如果在高级块(更靠近根)中找到删除,则应首先执行它,也许从较低级块中删除删除指令。我有哪些选择?对于每个删除存储,引用它的持有块(例如$remove[] = array('what-to-remove' =&gt; 'sub2', 'parent' =&gt; &amp;$sub))?

我希望有人能指出我正确的方向!如果有不清楚的地方,请评论!

【问题讨论】:

  • remove 是否意味着在解析 xml 时应该忽略 sub 或者应该在运行时将其删除?如果是后者,实际上什么时候应该删除?
  • 因为它是一个合并树,解析不能以线性方式完成,因为像remove 这样的指令几乎可以放置在任何地方,例如。在开始时(当尚未定义要删除的对象时)。而且,一些指令对“全局”范围有影响,其他指令只对它的包含块有影响。因此,删除 block 可能会导致删除 remove (当它存在时,它又会删除另一个块)。
  • 所以是的:虽然树应该尽可能早地被解析,但它应该在可能的最晚时刻被执行,以确保每个可能影响另一个指令的指令都已经可用。

标签: php oop scope hierarchy


【解决方案1】:

您可能可以使用一种 Register 类:

<?php

class Register {

    protected static $_instance;

    protected $_options = array();

    public static function getInstance() {
        if( null === self::$_instance ) {
            self::$_instance = new Register();
        }
        return self::$_instance;
    }

    // Assuming your option has a unique name
    public function registerOption( Option $option, Block $owner = null ) {
        $this->_options[$option->name] = array(
            'option' => $option,
            'owner'  => $owner
        );

        // Adds the option to the block if not exists
        if( null !== $owner && !$owner->hasOption($option) ) {
            $owner->addOption($option);
        }
    }

    public function removeOption( $optionName, $removeFromOwner = true ) {
        if( isset($this->_options[$optionName]) ) {
            if( $removeFromOwner ) {
                $owner = $this->_options[$optionName]['owner'];
                if( null !== $owner ) {
                    $owner->removeOption( $optionName );
                }
            }            

            unset( $this->_options[$optionName] );
        }

    }

}

当你在一个块中解析一个新选项时,你可以通过调用 Register::getInstance()->registerOption( $option, $owner ) 来注册它

在解析 XML 时,您可以将删除命令堆叠在包含要删除的选项名称的数组中(假设选项名称是唯一的,如果它们不是唯一的,您可能必须解决此解决方案)。

解析完所有内容后,您可以取消堆栈删除命令并调用 removeOption( $optionName ) 从寄存器和拥有该选项的块中删除该选项。

我是不是忘记了什么?

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 2010-11-18
    相关资源
    最近更新 更多