Java设计模式-装饰器模式

设计模式之装饰器模式

装饰器模式是一种结构型设计模式,可以做到在不改变原来对象功能的情况下,向原有的对象添加新的功能,起到一个装饰的作用。具体的做法是创建一个装饰器类,用来包装原有的类,在不改变原有类方法的情况下,为原有类添加新的功能。


来看一个例子,我们在外面吃饭,有很多食物,其中有烧烤和火锅。比如我们点了烧烤,但是觉得味道不够爽,所以我们选择让老板加盐,或者加辣椒,这里的加盐和加辣椒其实就是对事物起装饰作用。用代码实现如下:

创建Food接口

提供两个抽象方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface Food {
/**
* 返回描述
* @return
*/
String getDesc();

/**
* 返回价格
* @return
*/
String getCost();
}

创建实现接口的实现类

Barbecue实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class BarbecueFood implements Food {
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return "烧烤";
}

/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double cost = 3.0;
return String.format("最后价格:%s块", cost);
}
}

Hotpot实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class HotpotFood implements Food {
/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return "火锅";
}

/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double cost = 100.0;
return String.format("最后价格:%s块", cost);
}
}

创建装饰器基类

FoodDecorator是一个抽象类,其中组合Food类

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
public abstract class FoodDecorator implements Food {
protected Food food;

public FoodDecorator(Food food) {
this.food = food;
}

/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
return food.getDesc();
}

/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
return food.getCost();
}
}

创建SaltFoodDecorator装饰器类

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

public class SaltFoodDecorator extends FoodDecorator {

public SaltFoodDecorator(Food food) {
super(food);
}

/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
String result = "加盐的" + food.getDesc();

return result;
}

/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double salt = 2.0;
System.out.println(String.format("加盐多收%s块", salt));
String result = food.getCost() + " + " + salt + "块";

return result;
}
}

创建PepperFoodDecorator装饰器类

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
public class PepperFoodDecorator extends FoodDecorator {

public PepperFoodDecorator(Food food) {
super(food);
}

/**
* 返回描述
*
* @return
*/
@Override
public String getDesc() {
String result = "加盐的" + food.getDesc();

return result;
}

/**
* 返回价格
*
* @return
*/
@Override
public String getCost() {
Double pepper = 10.0;
System.out.println(String.format("加辣椒多收%s块", pepper));
String result = food.getCost() + " + " + pepper + "块";

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
public class Main {
public static void main(String[] args) {
//创建不用装饰器修饰的Food
Food food = new BarbecueFood();
display(food.getDesc());
display(food.getCost());
System.out.println("-------------分割线---------------");
//创建用SaltFoodDecorator装饰的Food
Food barbecue = new SaltFoodDecorator(new BarbecueFood());
display(barbecue.getDesc());
display(barbecue.getCost());
System.out.println("-------------分割线---------------");
//创建用PepperFoodDecorator装饰的Food
Food hotSpot = new PepperFoodDecorator(new HotpotFood());
display(hotSpot.getDesc());
display(hotSpot.getCost());
}

private static void display(Object obj) {
System.out.println(obj);
}

}

结果如下:

1
2
3
4
5
6
7
8
9
10
烧烤
最后价格:3.0
-------------分割线---------------
加盐的烧烤
加盐多收2.0
最后价格:3.0块 + 2.0
-------------分割线---------------
加盐的火锅
加辣椒多收10.0
最后价格:100.0块 + 10.0

来看一下类图会更加地清晰

END

装饰器模式在日常开发中也有很多应用,典型的就是JDK里面的IO。

InputStream代表输入流,输入来源可以是文件(FileInputStream)、管道(PipedInputStream)、数组(ByteArrayInputStream)等。就像上面的烧烤,火锅。FilterInputStream就是装饰器的基类,他的实现类是一系列的装饰器,比如BufferedInputStream可以用缓冲区来修饰InputStream,把InputSteam包装成有缓冲区的输入流。