php - 使用复合模式限制可以相互添加的对象类型

标签 php oop design-patterns

情况:我正在构建自定义 PHP 应用程序框架。我已经实现了一个复合模式,所以我可以构建一个对象树来表示要呈现的页面。示例:

abstract class \Block\BlockAbstract {
     protected _blocks = array();
     public function __construct($properties);
     public function getBlocks();
     public function addBlock($block);

     ...
}

我所有的“ block ”对象都继承自这个抽象类,它运行良好,在一点递归的帮助下渲染变得轻而易举。

问题: 我需要一种方法来验证哪些类的 block 可以添加到其他 block 中。例如,我必须考虑 4 种不同的 block 类型。请记住,所有 block 都继承自单个 block 抽象,这些是具体类的行为分类,不要与其他抽象混淆:

  • 泛型 - 泛型可以添加任何其他 block 类型

  • Final - 不能添加任何子 block 。

  • 父级 - 父级是一个只能添加特定类型子级的 block 它,但可以添加到任何通用

  • 子项 - 只能添加到特定的父项。此 block 还可以共享 Generic、Parent 或 Final 的属性

总结一下目标:给定一个具体的 block 类名称,生成一个包含所有可以添加到它的具体 block 类的列表。

目前提出的解决方案:

将名为“blockClassification”的属性添加到将其定义为通用、最终、父级或子级的 block 抽象,并将逻辑硬编码到验证函数中,该函数在 addBlock($block) 中调用方法。

出于多种原因我不喜欢这个解决方案,但主要是它仍然没有给我一个明确的途径来定义可以允许的具体 parent 和 child 是什么。例如,我有一个作为父类的具体类 \Block\Tabs。它只能添加\Block\Tabs\Panel block ,\Block\Tabs\Panel只能添加到\Block\Tabs。必须添加额外的属性来建立这些关系,并且可以检查这些属性来导出“ block 分类”,这使得这种方法不切实际。

将 allowedChildTypes 属性添加到定义可添加的具体类列表的 block 中。为了便于使用,2个值有特定的含义,*表示所有 block 类型,NULL值表示不能添加 block 。对于所有其他情况,提供逗号分隔的类名字符串,并且只允许那些类或从它们继承的类

我倾向于这个方向,因为 PHP 为我提供了 InstaceOf 运算符。我可以使用它来进行检查,当我有扩展基集的新具体类时,该检查将返回与其父类相同的结果。我唯一的犹豫是,虽然这种方法确实解决了“给定一个具体的 block 类名称,生成一个列表”的问题,但我觉得它在未来限制了我,因为我只能在树下进行搜索而不能返回向上。 IE。 “给定子 block 类名,生成可以添加到的父 block 列表”

我确信我不是唯一遇到过这个问题的人,所以我向大众提出的问题是:处理/解决这个问题的最佳方法是什么?

附加信息:

如果您想知道我首先是如何获得所有类的列表的,框架实现了 PSR-0,所以我正在扫描目录树以派生所有类名,然后动态实例化它们。

$allClassNames = scanDirectories(); // Returns array of strings ex: array('\Block\Classname1','\Block\Classname2'); 
foreach($allClassNames as $className){
  $object = new $className();
}

最佳答案

越来越多地思考这个问题,我认为可能有另一种方法来抽象它。

通用、最终、父和子类别似乎可以分为三个部分:通用、最终和自定义(其中父或子是特定的)

这三个部分可以用两个属性来解释:parent 和 child。

考虑一下:

                 parent                child
generic          /                     *
final            /blocks/tabs          null
parent           /blocks/              /blocks/tabs/       
child (generic)  /blocks/tabs/         *
child (final)    /blocks/tabs/         null
child (parent)   /blocks/tabs/         /blocks/popup/
  • generic block 有 parent/,作为根,可以有任何类型的 child
  • 最后一个 block 是/blocks/tabs/的子​​ block (因此下一个 block 示例,父 block ,可以将它作为子 block )并且不能有任何子 block
  • 父 block 可以添加到任何 block ,并且可以在标签中有子 block
  • child 可以附加到标签
  • 普通 child 可以有任何 child
  • 最后一个 child 不能有任何 child
  • parent child 可以有popup child

给定一个特定的 block ,您可以找到其父或子属性等于特定父或子属性的通用 block

关于php - 使用复合模式限制可以相互添加的对象类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23683731/

相关文章:

java - 如何将目录中的文件列表从 PHP 传递到 Android/Java

php - Yii2 Active Record JSON 响应,类型转换问题

php - SQL 连接错误 : Connection failed: Unknown MySQL server host 'localhost:3306' (0)

php - 在 Laravel 中使用 Mockery/phpUnit 时出错

oop - Julia - 检查对象是否具有属性

python - 添加后删除实例

r - 在R中,如何创建错误对象?以后如何在上面抛出错误?

C++ 单例类——继承的好习惯

c++ - RAII - 类指针和作用域

java - 如何在 Java 中实现具有内部依赖性的惰性评估有状态类?