原创设计模式之4:装饰模式
Posted 编程技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创设计模式之4:装饰模式相关的知识,希望对你有一定的参考价值。
点击蓝字之后,我们就是好朋友啦~
一、概念
装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。
定义一个抽象的装饰类,将具体的装饰类作为其子类,然后继承具体的装饰类。
二、使用场景
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。
使用装饰模式的步骤:
在装饰类的内部维护一个被装饰类的引用。
让装饰类有一个共同的父类或者是父接口。
三、UML结构图
四、代码示例
案例一:
Component:
1public interface Component {
2 public void operation();
3}
Decorator:
1public class Decorator implements Component{
2
3 //维持一个对抽象构件对象的引用
4 private Component component;
5
6 //注入一个抽象构件类型的对象(通过构造方法或者set方法)
7 public Decorator(Component component) {
8 this.component = component;
9 }
10
11 @Override
12 public void operation() {
13 //调用原有业务方法,此处没有真正的实现operation方法,具体的装饰过程交由子类完成
14 component.operation();
15 }
16
17}
ConcreateDecorator:
1public class ConcreateDecorator extends Decorator{
2
3 public ConcreateDecorator(Component component) {
4 super(component);
5 }
6
7 public void operation(){
8 //调用原有业务方法
9 super.operation();
10 //调用新增业务方法
11 addedBehavior();
12 }
13
14 //新增业务方法
15 public void addedBehavior(){
16
17 }
18
19}
案例二:
使用继承的方式增强一个类的功能:
1package com.hcx.pattern;
2
3import java.io.BufferedReader;
4import java.io.File;
5import java.io.FileNotFoundException;
6import java.io.FileReader;
7import java.io.IOException;
8import java.io.Reader;
9
10/**
11 * 拓展BufferedReader的功能, 增强readLine方法,返回的字符串带有行号。
12 * @author hcx
13 *
14 */
15class BufferedLineNum extends BufferedReader{
16 //行号
17 int count = 1;
18
19 public BufferedLineNum(Reader in) {
20 super(in);
21 }
22
23 @Override
24 public String readLine() throws IOException {
25 String line = super.readLine();
26 if(line==null) {
27 return null;
28 }
29 line = count+" "+line;
30 count++;
31 return line;
32 }
33
34}
35
36/**
37 * 带分号的缓冲输入字符流
38 * @author hcx
39 *
40 */
41class BufferedSemi extends BufferedReader{
42
43 public BufferedSemi(Reader in) {
44 super(in);
45 }
46
47 @Override
48 public String readLine() throws IOException {
49 String line = super.readLine();
50 if(line==null) {
51 return null;
52 }
53 line = line+";";
54 return line;
55
56 }
57
58}
59
60/**
61 * 带双引号的缓冲输入字符流
62 * @author hcx
63 *
64 */
65class BufferedQuto extends BufferedReader{
66
67 public BufferedQuto(Reader in) {
68 super(in);
69 }
70
71 @Override
72 public String readLine() throws IOException {
73 String line = super.readLine();
74 if(line == null) {
75 return null;
76 }
77 line = "\""+line+"\"";
78 return line;
79 }
80
81}
82public class Demo1 {
83
84 public static void main(String[] args) throws IOException {
85 File file = new File("F:\\Demo1.java");
86 //建立数据的输入通道
87 FileReader fileReader = new FileReader(file);
88 //建立带行号的缓冲输入字符流
89 BufferedLineNum bufferedLineNum = new BufferedLineNum(fileReader);
90
91 //带有分号的缓冲输入字符流
92 BufferedSemi bufferedSemi = new BufferedSemi(fileReader);
93
94 //带有双引号的缓冲输入字符流
95 BufferedQuto bufferedQuto = new BufferedQuto(fileReader);
96
97 String line = null;
98 while((line = bufferedLineNum.readLine())!=null) {
99 System.out.println(line);
100 }
101 }
102
103}
使用装饰模式增强一个类的功能:
1package com.hcx.pattern;
2
3import java.io.BufferedReader;
4import java.io.File;
5import java.io.FileReader;
6import java.io.IOException;
7import java.io.Reader;
8
9/**
10 * 带行号的缓冲输入字符流
11 * @author hcx
12 *
13 */
14class BufferedLineNum2 extends BufferedReader{
15
16 //在内部维护一个被装饰类的引用。
17 BufferedReader bufferedReader;
18
19 int count = 1;
20
21 public BufferedLineNum2(BufferedReader bufferedReader) {
22 // 注意: 该语句没有任何的作用,只不过是为了让代码不报错。
23 super(bufferedReader);
24 this.bufferedReader = bufferedReader;
25 }
26
27 public String readLine() throws IOException {
28 String line = bufferedReader.readLine();
29 if(line==null) {
30 return null;
31 }
32 line = count+" "+line;
33 count++;
34 return line;
35
36 }
37
38}
39
40/**
41 * 带分号缓冲输入字符流
42 * 继承的原因:为了让这些装饰类的对象可以作为参数进行传递,达到互相装饰的效果。
43 * @author hcx
44 *
45 */
46class BufferedSemi2 extends BufferedReader{
47
48 //在内部维护一个被装饰类的引用。
49 BufferedReader bufferedReader;
50
51 public BufferedSemi2(BufferedReader bufferedReader) {
52 //BufferReader没有无参的构造方法,继承了BufferedReader,所以要指定调用父类的带参的构造方法
53 super(bufferedReader);// 注意: 该语句没有任何的作用,只不过是为了让代码不报错。
54 this.bufferedReader = bufferedReader;
55 }
56
57 public String readLine() throws IOException{
58 //创建该类对象时,如果传入的是buffereLineNum,则这里的ReadLine方法是调用了buffereLineNum的readLine方法.
59 String line = bufferedReader.readLine();
60 if(line==null){
61 return null;
62 }
63 line = line +";";
64 return line;
65 }
66}
67
68/**
69 * 带双引号缓冲输入字符流
70 * @author hcx
71 *
72 */
73class BufferedQuto2 extends BufferedReader{
74
75 //在内部维护一个被装饰的类
76 BufferedReader bufferedReader;
77
78 public BufferedQuto2(BufferedReader bufferedReader){ //new BufferedSemi2();
79 super(bufferedReader) ; //只是为了让代码不报错
80 this.bufferedReader = bufferedReader;
81 }
82
83 public String readLine() throws IOException{
84 //创建该类对象时,如果传入的是bufferedSemi2,则这里的ReadLine方法是调用了bufferedSemi2的readLine方法.
85 String line = bufferedReader.readLine();
86 if(line==null){
87 return null;
88 }
89 line = "\""+line +"\"";
90 return line;
91 }
92
93
94}
95
96
97public class Demo2 {
98
99 public static void main(String[] args) throws IOException {
100 File file = new File("F:\\Demo1.java");
101 FileReader fileReader = new FileReader(file);
102 //建立缓冲输入字符流
103 BufferedReader bufferedReader = new BufferedReader(fileReader);
104 //建立带行号的缓冲输入字符流
105 BufferedLineNum2 bufferedLineNum = new BufferedLineNum2(bufferedReader);
106
107 //带分号的缓冲输入字符流
108 BufferedSemi2 bufferedSemi2 = new BufferedSemi2(bufferedLineNum);
109
110 //带双引号的缓冲输入字符流
111 BufferedQuto2 bufferedQuto2 = new BufferedQuto2(bufferedSemi2);
112
113 String line = null;
114 while((line = bufferedQuto2.readLine())!=null){
115 System.out.println(line);
116 }
117 }
118
119}
案例三:
一家三口每个人都会工作,儿子的工作就是画画,母亲的工作就是在儿子的基础上做一个增强,不单止可以画画,还可以上涂料。爸爸的工作就是在妈妈基础上做了增强,就是上画框。
1interface Work{
2
3 public void work();
4}
5
6class Son implements Work{
7
8 @Override
9 public void work() {
10 System.out.println("画画");
11 }
12}
13
14
15class Mather implements Work{
16
17 //需要被增强的类。
18 Work worker;
19
20 public Mather(Work worker){
21 this.worker = worker;
22 }
23
24 @Override
25 public void work() {
26 worker.work();
27 System.out.println("给画上颜色");
28 }
29}
30
31
32class Father implements Work{
33
34 //需要被增强的类的引用
35 Work worker;
36
37 public Father(Work worker){
38 this.worker = worker;
39 }
40
41
42 @Override
43 public void work() {
44 worker.work();
45 System.out.println("上画框");
46 }
47
48}
49
50public class Demo {
51
52 public static void main(String[] args) {
53 Son s = new Son();
54// s.work();
55 Mather m = new Mather(s);
56// m.work();
57 Father f = new Father(s);
58 f.work();
59
60 }
61}
总结:
继承实现的增强类和装饰模式实现的增强类有何区别?
继承实现的增强类:
优点:代码结构清晰,而且实现简单.
缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大。
装饰模式实现的增强类:
优点:内部可以通过多态技术对多个需要增强的类进行增强,可以使这些装饰类达到互相装饰的效果。使用比较灵活。
缺点:需要内部通过多态技术维护需要被增强的类的实例。进而使得代码稍微复杂。
五、装饰模式的优点
对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增长。
可以通过一种动态的方式来扩展一个对象的功能
可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合。
推荐↓↓↓ 编程技术
以上是关于原创设计模式之4:装饰模式的主要内容,如果未能解决你的问题,请参考以下文章
通俗易懂,值得收藏的 java 设计模式实战,装饰者模式 之 你不用改变,就让你的能力变强了