装饰者模式

定义

修饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能

修饰者模式的作用

通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

时序图


ConcreteComponent:具体的组件对象,实现了组件接口。该对象通常就是被装饰器装饰的原始对象,可以给这个对象添加职责;

Decorator:所有装饰器的父类,需要定义一个与组件接口一致的接口(主要是为了实现装饰器功能的复用,即具体的装饰器A可以装饰另外一个具体的装饰器B,因为装饰器类也是一个Component),并持有一个Component对象,该对象其实就是被装饰的对象。如果不继承组件接口类,则只能为某个组件添加单一的功能,即装饰器对象不能在装饰其他的装饰器对象。

ConcreteDecorator:具体的装饰器类,实现具体要向被装饰对象添加的功能。用来装饰具体的组件对象或者另外一个具体的装饰器对象。

代码实现


例子描述
首先调用原函数的方法,计算奶茶的售价,然后继承原来的奶茶,然后加入其他的原料,得到红豆奶茶,使用组合的方式把原来的参数传递给装饰对象,然后重写一下cost*()方法去计算后来的奶茶的价格,打印出来

代码实现

抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package decoratortest;
/**
*
* @author lxh
* @version 1.0
*
*/
public abstract class MilkyTea {
String description="Unknow Tea";
public String getDescription(){
return description;
}
public abstract double cost();
}

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
41
42
43
44
45
46
47
48
49
50
/*---
实现抽象类
package decoratortest;
public class BeanMilkeTea extends MilkyTea{
public BeanMilkeTea(){
description="Tea";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.3;
}
}
装饰对象
package decoratortest;
public abstract class CondimentDecorator extends MilkyTea {
public abstract String getDescription();
}
装饰修饰者
package decoratortest;
public class RedBeanMilkTea extends CondimentDecorator {
MilkyTea milkyTea;
@Override
public String getDescription() {
// TODO Auto-generated method stub
return milkyTea.description+",redbean";
}
@Override
public double cost() {
// TODO Auto-generated method stub
return 0.14+milkyTea.cost();
}
public RedBeanMilkTea(MilkyTea milkyTea) {
super();
this.milkyTea = milkyTea;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package decoratortest;
/**
*
* @author lxh
* @deprecated 装饰模式
*
*/
public class DecoratorTest {
public static void main(String[] args) {
MilkyTea milkTea = new BeanMilkeTea();
System.out.println(milkTea.getDescription() + " " + "$" + milkTea.cost());
MilkyTea milkTea1 = new RedBeanMilkTea(milkTea);
System.out.println(milkTea1.getDescription() + "$" + milkTea1.cost());
}
}
/*---

结果
Tea $0.3
Tea,redbean$0.44

装饰者的应用(来自书上)

Java中的IO是明显的装饰器模式的运用。FilterInputStream,FilterOutputStream,FilterRead,FilterWriter分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream,OutputStream,Reader,Writer类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。继承自InputStream,OutputStream,Reader,Writer这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream,FilterOutputStream,FilterRead,FilterWriter这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream是InputStream的一个子类,从文件中读取数据流,BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream装饰FileInputStream,就可以提供一个内存缓冲区来保存从文件中读取的输入流。

代码实现

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
package decoratortest1;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class LowerCaseInputStream extends FilterInputStream{
protected LowerCaseInputStream(InputStream in) {
super(in);
// TODO Auto-generated constructor stub
}
public int read()throws IOException{
int c=super.read();
return (c==-1?c:Character.toLowerCase((char) c));
}
public int read(byte[] b,int offset,int len) throws IOException{
int result=super.read(b, offset, len);
for(int i=offset;i<offset+result;i++){
b[i]=(byte) Character.toLowerCase((char)b[i]);
}
return result;
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package decoratortest1;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputTest {
public static void main(String[] args) throws IOException {
int c;
try{
InputStream in=new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("src/test.txt")));
while((c=in.read())>=0){
System.out.println((char)c);
}
in.close();
}catch(IOException e){
e.printStackTrace();
}
}
}

总结

通过本次实现,对各种接口的修饰和扩展有了进一步的了解,为以后书写和架构提供了更好的平台,学习设计模式,就是学习作者的写作风格和写代码的思考,在成长中学到更多的东西

文章目录
  1. 1. 定义
  2. 2. 修饰者模式的作用
  3. 3. 时序图
  4. 4. 代码实现
    1. 4.1. 代码实现
  5. 5. 装饰者的应用(来自书上)
  6. 6. 代码实现
  7. 7. 总结
,