管道-过滤器结构模式
- 简介
- 代码实现
- 1、定义一个管道接口
- 2、定义一个管道上下文流转抽象
- 3、定义一个抽象阀门
- 4、实现管道接口
- 5、定义阀门
- 按照业务逻辑组装管道-阀门
简介
在管道和过滤器软件体系结构中,每个模块都有一个输入和一个输出。它采用流水线的方式对数据进行作业。类似我们生活中的管道,过滤器相当于管道上的阀门。我们在每个阀门上进行一定的数据计算,并将得到的结果传递给下个阀门。这种有序的数据处理就是我们所说的管道-过滤器模式。
它的优点在于可以将整个计算提示分解为多个计算行为的叠加组合,通过管道过滤器结构我们可以将复杂的计算分解,达到化烦为简的目的。同时任意两个过滤只要他们遵守同样的要约,那么他们就可以进行组合,这一点可以提高代码的复用。同时过滤器的顺序可以自由调节,程序设计灵活多变。学习管道过滤器模式我们需要了解两个属于
Pipeline:管道,相当于车间的生产线,是一套明确的逻辑处理总线。
Valve: 阀门,相当于生产线上的工人,负责完成各自职责内的工作。
那么我们如何实现管道过滤器模式呢?
代码实现
1、定义一个管道接口
/**
* @author FeianLing
* @date 2019/7/12
*/
public interface Pipeline {
/**
* @author FeianLing
* @date 2019/7/12
* @desc 设计基础阀门,一个管道必须基本有一个基本阀门
* @param [bases]
* @return void
*/
boolean setBases(AbstractValve valve);
/**
* @author FeianLing
* @date 2019/7/12
* @desc 添加阀门信息
* @param [valve]
* @return void
*/
boolean addValve(AbstractValve valve);
/**
* @author FeianLing
* @date 2019/7/12
* @desc 移除管道中的阀门
* @param [valve]
* @return void
*/
boolean removeValve(AbstractValve valve);
/**
* @author FeianLing
* @date 2019/7/12
* @desc 调用管道处理数据
* @param []
* @return void
*/
void invoke();
}
2、定义一个管道上下文流转抽象
public interface PipelineContext {
/**
* @author FeianLing
* @date 2019/7/12
* @desc 调用下一个阀门
* @param []
* @return void
*/
void invokeNext();
}
3、定义一个抽象阀门
public abstract class AbstractValve {
/**
* @author FeianLing
* @date 2019/7/12
* @desc 当前阀门需要的处理逻辑
* @param [context] d.
* @return void
*/
abstract void execute(PipelineContext context);
/**
* @author FeianLing
* @date 2019/7/12
* @desc 调用阀门
* @param [context]
* @return void
*/
void invoke(PipelineContext context) {
execute(context);
context.invokeNext();
}
}
4、实现管道接口
public class StandardPipeline implements Pipeline {
/** 阀门集合 */
private List<AbstractValve> valves;
/** 基础阀门 */
private AbstractValve bases;
/** 管道流转的上下文,可根据业务需要在上下文中加入流转的数据 */
private PipelineContext context;
public StandardPipeline() {
valves = new ArrayList<>();
context = new StandardPipelineContext();
}
@Override
public boolean setBases(AbstractValve valve) {
bases = valve;
return true;
}
@Override
public boolean addValve(AbstractValve valve) {
return valves.add(valve);
}
@Override
public boolean removeValve(AbstractValve valve) {
if (valves.contains(valve)) {
return valves.remove(valve);
}
return true;
}
@Override
public void invoke() {
context.invokeNext();
}
/** 定义一个管道上下文内部类 实现管道上下文接口 */
private class StandardPipelineContext implements PipelineContext {
int index = 0;
@Override
public void invokeNext() {
if (!valves.isEmpty() && index < valves.size()) {
valves.get(index++).invoke(context);
} else {
bases.execute(context);
}
}
}
}
5、定义阀门
//首先定义一个基础的阀门
@Slf4j
public class BaseValve extends AbstractValve {
@Override
void execute(PipelineContext context) {
log.info("BaseValve > invoke > {}", context);
}
}
//下面我们在定义几个阀门来测试
@Slf4j
public class Valve1 extends AbstractValve {
@Override
void execute(PipelineContext context) {
log.info("Valve1 > invoke >{}", context);
}
}
@Slf4j
public class Valve2 extends AbstractValve {
@Override
void execute(PipelineContext context) {
log.info("Valve2 > invoke > {}", context);
}
}
@Slf4j
public class Valve3 extends AbstractValve {
@Override
void execute(PipelineContext context) {
log.info("Valve3 > invoke > {}", context);
}
}
按照业务逻辑组装管道-阀门
管道组装代码如下所示,我们预期的数据处理流转是 阀门1 -> 阀门3 ->阀门2 -> 基础阀门。
public class PipelineTest {
public static void main(String[] args) {
StandardPipeline pipeline = new StandardPipeline();
BaseValve baseValve = new BaseValve();
Valve1 valve1 = new Valve1();
Valve2 valve2 = new Valve2();
Valve3 valve3 = new Valve3();
pipeline.setBases(baseValve);
pipeline.addValve(valve1);
pipeline.addValve(valve3);
pipeline.addValve(valve2);
pipeline.invoke();
}
}
通过执行main方法,打印结果如下。