我必须设计像Filter
接口表示的过滤器这样的实体,声明可以应用于Content对象的apply(Content content)
方法。过滤器可以组合在一起,类似于工作流程,但这些是动态的。例如,如果FilterA返回X,那么我将应用filterB,而接收结果Y将导致应用FilterC。过滤器链是特定于应用程序的,我还没有决定如何构建过滤器链。
我会以与某些工作流框架相同的方式设计此行为:管理器组件迭代过滤器列表,并在每个过滤器上调用filter.apply(content)
。但是如何允许像if / else语句这样的动态?
现在我构思了一个Workflow或FilterChain接口,声明了getNextFilter(previousResult)
。实现此接口可以声明特定于应用程序的工作流。但是Workflow接口的实现将很无聊:要跟踪当前步骤(整数?)然后在每次getNextFilter()
调用时,通过switch / case语句确定哪个过滤器将成为下一个?!?< / p>
哪种解决方案可能更好?如何申报连锁?
我正在使用Java和Spring,因此可以使用IoC。
答案 0 :(得分:2)
对于这种情况,我会尝试对链进行建模,并通过提供更多的&#34;智能&#34;来将执行的责任转移到链本身。到节点。在某种程度上,我会将节点视为命令,因为它们可以自己执行,并且通过具有公共接口,可以创建composites。 (顺便说一下,我不是Java程序员,所以请原谅我可能的语法错误)。所以,我的主要设计决定是:
我首先要定义类似的东西:
public abstract class ChainNode {
public abstract Content apply(Content content);
}
/**
The NullObject of the chain
http://www.oodesign.com/null-object-pattern.html
*/
public class FinalNode extends ChainNode {
public Content apply(Content content) {
return content;
}
}
/** A sample filter */
public class FilterA extends ChainNode {
private ChainNode nextNode;
FilterA(ChainNode nextNode) {
this.nextNode = nextNode;
}
public Content apply(Content content) {
filteredValue = //Apply the filter
return nextNode.apply(filteredValue);
}
}
/** An if-then-else filter */
public abstract class ConditionalFilter extends ChainNode {
private ChainNode trueFilter;
private ChainNode falseFilter;
ConditionalFilter(ChainNode trueFilter, ChainNode falseFilter) {
this.trueFilter = trueFilter;
this.falseFilter = falseFilter;
}
public Content apply(Content content) {
if (this.evalCondition(content)) {
return this.trueFilter.apply(content);
}
else {
return this.falseFilter.apply(content);
}
}
private abstract boolean evalCondition(Content content);
}
使用此方法,您正在做的是将控制结构转换为对象并要求它们执行,这甚至允许您创建与标准if-then或switch语句不同的逻辑。有了这个基础,你可以创建一个具有不同分支操作符的链,触发不同的过滤路径。
需要注意的一些事项是:
Content
的内容,实际上允许您将一个过滤器链接到另一个过滤器。我想你的要求确实如此,但我不确定。apply
方法。ConditionalFilter
继承并重新定义evalCondition
方法。我不知道Java是否有闭包(我认为它没有),但如果它有,你可以改为添加一个condition
实例变量并用闭包进行参数化,从而避免每个变量的子类化新条件。或者也许在Java世界中有一个更为公认的解决方法,我只是不知道:(。content
参数决定的。如果您需要更多信息来做出决定,您还可以在apply
方法中传递上下文对象。根据您的需要,如果您需要更多的灵活性,这可以是结构化对象,也可以只是字典。最后,关于链条的构造,如果链条长而复杂,我认为这里的builder应该适合您的需要。
HTH
答案 1 :(得分:2)
为了一般性我假设,条件不仅应该在单个过滤器之间决定,还应该在过滤器链之间决定。
经过一番思考后,在我看来Composite Pattern非常适合这里。
Component
:您的Filter
界面Leafs
:具体过滤器Composite
:您的“工作流程或FilterChain界面” ConditionalFilter
可以是Leaf
或Composite
。
在这两种情况下,使用比较和两个Filter
对象初始化,它可以分支在单个过滤器或过滤器工作流程上。
答案 2 :(得分:1)
这是在php中实现过滤器链的复合模式的例子。
$filter = new BookFilter\Chain();
$filter->appendFilter(new BookFilter\Isbn('978-5-8459-1597-9'))
->appendFilter(new BookFilter\Title('Domain Driven', BookFilter\Title::CONTAINS))
->appendFilter(new BookFilter\Publisher('Вильямс', BookFilter\Publisher::EQUALS))
->appendFilter(new BookFilter\Price(100, 10.000))
->appendFilter(new BookFilter\Ebook(true));
$bookCollection = $bookSeachService->findAllByFilter($filter);
从这里采取:http://crazycode.net/blog/6-architecture/10-structural-patterns
答案 3 :(得分:0)
由于您只是想按顺序执行过滤器链,因此最简单的方法是将过滤器链实现为List<Filter>
。你可以对它们进行循环并执行。
类似的东西(注意这显然是我没试过的快速实现):
public class FilterChainImpl implements FilterChain {
private List<Filter> filterChain = new ArrayList<Filter>();
public addFilter(final Filter f) {
filterChain.add(f);
}
public apply(final Content content) {
Content prevContent = content;
for(Filter f : filterChain) {
prevContent = f.apply(prevContent);
}
}
}
然后您可以使用它来一般性地创建您喜欢的任何过滤器链。如果要使用许多不同的过滤器链,可以使用一些工厂技术来创建过滤器链。
答案 4 :(得分:0)
这里需要的是模式Chain of Responsibility。
在Java中实现了这么多次,我的建议是:
参与机制应该是一个接口,这样你就可以拥有专门的代理,这些代理做了很多不同的事情,只同意接收消息并根据接口指令传递它们。
如果您想逐步过滤,可以按照问题中的显示传递内容,每个参与者都可以对其进行变更。我在GitHub上有一个名为scraper的开源项目,该项目使用责任链来实现代理链,这些代理链提取被包含内容的页面部分。