抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

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;
}

/**
* 添加阀门
*
* @param 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,它持有一个头阀门和一个尾阀门,它按照添加阀门顺序的方式构造阀门链表,按照队列的形式,先添加的先调用。

评论