设计模式之装饰者模式

什么是装饰者模式?

定义:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

设计原则

1.开闭原则,即对修改关闭,对扩展开放
2.多用组合,少用继承

以咖啡店售卖咖啡为例

咖啡是所有咖啡和咖啡调味品的基类

1
2
3
4
5
6
7
8
9
public abstract class Coffee {
protected String name;
public String getName(){
return name;
}
public abstract double getPrice();
}

创建一个摩卡咖啡继承自该基类

1
2
3
4
5
6
7
8
9
10
11
public class Mocha extends Coffee {
public Mocha(){
name = "摩卡咖啡";
}
@Override
public double getPrice() {
return 20;
}
}

再来一个调味品抽象类继承咖啡基类,该类是所有调味品的父类

1
2
3
public abstract class Condiment extends Coffee {
public abstract String getName();
}

具体的咖啡装饰者继承自调味品类(给咖啡加点糖)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Sugar extends Condiment {
Coffee coffee;
public Sugar(Coffee coffee){
this.coffee = coffee;
}
@Override
public String getName() {
return coffee.getName()+",加糖";
}
@Override
public double getPrice() {
return 1+coffee.getPrice();
}
}

再给咖啡加点奶

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Milk extends Condiment {
Coffee coffee;
public Milk(Coffee coffee){
this.coffee = coffee;
}
@Override
public String getName() {
return coffee.getName()+",加牛奶";
}
@Override
public double getPrice() {
return 2+coffee.getPrice();
}
}

好了,我们来写一个测试类测试一下

1
2
3
4
5
6
7
8
9
10
public class Test {
public static void main(String[] args){
Coffee coffees = new Mocha();
System.out.println(coffees.getName()+"-价格-"+coffees.getPrice());
Sugar sugars = new Sugar(coffees);
System.out.println(sugars.getName()+"-价格-"+sugars.getPrice());
Milk milks = new Milk(sugars);
System.out.println(milks.getName()+"-价格-"+milks.getPrice());
}
}

输出结果
摩卡咖啡-价格-20.0
摩卡咖啡,加糖-价格-21.0
摩卡咖啡,加糖,加牛奶-价格-23.0

总结

如果有再多一个装饰者我们只需要扩展一个类去继承自调味品类,然后去装饰咖啡就行了。同样的再多一个咖啡品种我们只需要去继承自咖啡的基类就行了。java的io实现也是装饰者模式,都是围绕着InputStream或者OutputStream两个基类去扩展的。