JAVA设计模式-管道模式(pipeline)
什么是管道模式
管道模式用于将复杂的进程分解成多个独立的子任务。每个独立的任务都是可复用的,因此这些任务可以被组合成复杂的进程。
这种模式允许你将庞大的进程分解成更小的子任务,这些子任务将数据进行处理并将处理后的结果传递给下一个子任务。就像流水线一样,有条不紊,从原料加工到成品,实现一道完整的工序。
管道中的每一个任务都会接受并返回同一类型的数据,这样子任务可以在管道中被添加、移除或者替换,而不影响其它子任务。
角色
- **阀门(valve): ** 处理数据的节点
- 管道(pipeline):组织各个阀门
- 客户类(Client):构造管道,并调用
优缺点
优点
将复杂的处理流程分解成独立的子任务,从而方便测试每个子任务;
被分解的子任务可以被不同的处理进程复用,避免代码冗余。
在复杂进程中添加、移除和替换子任务非常轻松,对已存在的进程没有任何影响。
缺点
虽然每个子任务变得简单了,但是当你再度尝试将这些子任务组合成完整进程时有一定复杂性;
此外你还需要保证独立子任务测试通过后整体的流程能正常工作,这有一定的不确定性。
当你看到的都是一个个子任务时,对理解整体流程带来困难(盲人摸象的故事想必大家很熟悉,正是此理)。
适用场景
- 工作流的参考模型
- 服务framework的参考构建模型
- 可动态指定一组对象处理请求。
实现
接口代码
阀门接口
1 2 3 4 5 6 7
| public interface Valve { public Valve getNext();
public void setNext(Valve v);
public void invoke(String s); }
|
管道接口
1 2 3 4 5 6 7 8 9
| public interface Pipeline { public Valve getFirst();
public Valve getBasic();
public void setBasic(Valve v);
public void addValve(Valve v); }
|
阀门实现
基础阀门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class BasicValve implements Valve {
protected Valve next;
public Valve getNext() { return next; }
public void setNext(Valve valve) { next = valve; }
public void invoke(String s) {
System.out.println("调用基础阀门"); } }
|
普通阀门
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class SecondValve implements Valve { public Valve next; public Valve getNext() { return next; }
public void setNext(Valve v) { next = v; }
public void invoke(String s) { System.out.println("执行SecondValve阀门,并掉调用下一个阀门"); getNext().invoke(s); } }
public class ThirdValve implements Valve { public Valve next;
public Valve getNext() { return next; }
public void setNext(Valve v) { next = v; }
public void invoke(String s) { System.out.println("执行ThirdValve阀门,并掉调用下一个阀门"); getNext().invoke(s); } }
|
流水线实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class StandardPipeline implements Pipeline { protected Valve first; protected Valve basic;
public Valve getFirst() { return first; }
public Valve getBasic() { return basic; }
public void setBasic(Valve v) { basic = v; }
public void addValve(Valve v) { if (first == null) { first = v; v.setNext(basic); } else { Valve current = first; while (current != null) { if (current.getNext() == basic) { current.setNext(v); v.setNext(basic); break; } current = current.getNext(); } } } }
|
客户端调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class PiplineTest { public static void main(String[] args) { String s = "test"; StandardPipeline pipeline = new StandardPipeline(); BasicValve basic = new BasicValve(); SecondValve second = new SecondValve(); ThirdValve third = new ThirdValve(); pipeline.setBasic(basic); pipeline.addValve(second); pipeline.addValve(third); pipeline.getFirst().invoke(s); } }
|
执行结果
1 2 3
| 执行SecondValve阀门,并掉调用下一个阀门 执行ThirdValve阀门,并掉调用下一个阀门 调用基础阀门
|
总结
- 阀门的实现分两种,即普通阀门和尾阀门。普通阀门在处理完自己的事情之后,必须调用getNext.invoke(s)方法,也就是交给下一个阀门处理;而尾阀门不用调用这个方法,因为它是结束的那个阀门。
- 流水线实现类的主要逻辑在addValve,它持有一个头阀门和一个尾阀门,它按照添加阀门顺序的方式构造阀门链表,按照队列的形式,先添加的先调用。