所以我想做以下事情,我真的只是在寻找关于如何设计它的建议。
- 我有
Filter
可以在某些实体类型上运行的 s Filter
必须Rule
定义自己的行为Filter
s 处理实体,使用它们的规则,并返回一个布尔值- 作为一个具体的例子,我可能想过滤掉给定字段上的某些正则表达式被拒绝,我可以为它定义规则。我也可以有不同的规则,在同一个过滤器中使用简单的前缀匹配。
所以我想出了以下内容
interface FilterInterface
{
/**
* Load the rules for this filter
*/
function loadRules();
/**
* Filter an entity in an optional context
* @param mixed $entity Should return true for $this->supportsEntity($entity)
* @param array $context Other information
*
* @return boolean True if the $entity passes this filter
*/
function filter($entity, $context = array());
/**
* Check if filter supports the entity type
* @param mixed $entity
*
* @return boolean true if this Filter can be run for that entity type
*/
function supportsEntity($entity);
}
然后我打算做:
class ImageFilter implements FilterInterface
这将从数据库中加载规则并实现过滤器。
所以最初我虽然有一个像
FilterRule
:
- 范围(枚举类型来定义哪个过滤器使用它)
- 类型(可以有不同类型的规则,比如我提到的正则表达式与前缀)
- 值(字符串,取决于规则的类型)
并且会在范围设置为某个常量的地方ImageFilter
加载s 。FilterRule
然后ImageFilter
会做繁重的检查过滤器类型并将其应用于实体,一个接一个。以下伪代码演示了这一点。
public function filter($entity)
{
foreach ($this->rules as $rule) {
switch($rule->getType()) {
case RULE_TYPE_REGEX:
$this->doRegex();
break;
case RULE_TYPE_PREFIX:
$this->doPrefix();
break;
}
}
}
但后来我想知道,该实体是否应该对上述switch
区块负责?所以它会变成这样:
public function filter($entity)
{
foreach ($this->rules as $rule) {
$rule->process($entity);
}
}
这对我来说似乎更干净,Filter
只要“范围”正确,它就不关心新规则以及如何处理它们。 但我的印象是实体应该是简单的 POPO,所以看起来这种逻辑是一种不好的模式(但我从来没有 100% 确定实体应该真正做多少)。
我还考虑过使用继承映射,因此每个Rule
“类型”都可以是不同的类,并且它的逻辑非常简单(最多只有几行)。最后,我在想也许不同类型的Rule
应该以某种方式使用组合来产生“行为”或可以完成实际工作的东西......
所以总结一下,这是我目前的想法:
Filter
做所有的工作检查类型Rule
并采取相应的行动。Rule
只是一个“愚蠢”的实体来保存一些字符串Rule
完成检查自己的类型并对给定实体做某事的所有工作。现在Rule
实体有点“胖”但它隐藏了实现Filter
并且Filter
不需要更改以添加新Rule
类型Rule
使用继承来做上述,实际上是相同的想法,但没有更多的switch
声明- 2. 或 3. 但
Rule
为每种类型实例化不同的“行为”对象(不真正使用依赖注入似乎很糟糕,封装行为似乎是一个很好的设计) - 结合 1. 和 4. 这样就
Filter
可以得到正确的行为Rule
(现在可以像“行为”工厂一样使用依赖注入)
我想我越想越倾向于最后几个选项,但我不知道这方面的最佳实践。我确信这是一个相对常见的例子,所以我希望得到一些关于采取哪个方向的意见。(抱歉这么长的问题,希望它足够完整,可以回答)