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

时间:2014-05-15 16:21:05

标签: php oop design-patterns

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

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

     ...
}

我的所有“块”对象都继承自这个抽象类,它在一点点递归的帮助下运行得非常好。

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

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

  • 最终 - 不能添加任何子块。

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

  • Child - 只能添加到特定父级。此块还可以共享Generic,Parent或Final

  • 的属性

总结目标:给定具体的块类名称,生成可添加到其中的所有具体块类的列表。

目前提出的解决方案

将一个名为“blockClassification”的属性添加到块抽象中,将其定义为Generic,Final,Parent或Child,并将逻辑硬编码到从addBlock($ block)调用的validate函数中方法

我不喜欢这个解决方案有很多原因,但主要是它仍然没有给我一个明确的路径来定义具体的父母和孩子可以被允许的东西。例如,我有一个具体的类 \ Block \ Tabs ,它是父类。它只能添加 \ Block \ Tabs \ Panel 块,而 \ Block \ Tabs \ Panel 只能添加到 \ Block \ Tabs 。必须添加其他属性来构建这些关系,并且可以检查这些属性以导出“块分类”,使得这种方法不切实际。

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

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

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

其他信息:

如果你想知道我是如何获得所有类的列表的,那么框架实现了PSR-0,所以我扫描目录树以派生所有类名,然后动态实例化它们。 / p>

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

1 个答案:

答案 0 :(得分:1)

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

通用,最终,父和子类别似乎能够分为三个部分:通用,最终和自定义(父或子是特定的)

这三个部分可以用两个属性来解释:父母和孩子。

考虑一下:

                 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/
  • 通用块具有父/,是根,并且可以具有任何类型的子
  • 最后一个块是/ blocks / tabs /的子节点(所以下一个块示例,父节点,可以将它作为子节点)并且不能有任何子节点
  • 父块可以添加到任何块,并且可以在选项卡中包含子项
  • 可以将儿童附加到标签
  • 普通儿童可以有任何孩子
  • 最后一个孩子不能有任何chid
  • 父子可以有弹出孩子

给定一个特定的块,您可以找到父或子属性等于特定父或子属性的常规块