摘要
动态的给一个对象添加额外的功能,装饰者模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
适用环境
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
- 处理那些可以撤销的职责
- 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数量爆炸增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
参与者
-
Component
(抽象构件角色)真实对象和装饰对象有相同的接口,这样,客户端对象就能够以与真实对象相同的方式同装饰对象进行交互。
-
ConcreteComponent
(具体构件角色,即真实对象)IO流中的
FileInputStream
、FileOutputStream
-
Decorator
(装饰角色)持有一个抽象构件的引用。装饰对象接受所有客户端的请求,并把这些请求转发给真实的对象。这样,就能在真实对象调用前后增加新的功能。
-
ConcreteDecorator
(具体装饰角色)负责给构件对象增加新的责任。
-
类图
涉及角色
- 抽象组件:定义一个抽象接口,来规范准备附加功能的类。
- 具体组件:将要被附加功能的类,实现抽象构件角色接口。
- 抽象装饰者:持有对具体构件角色的引用并定义与抽象构件角色一致的接口。
- 具体装饰:实现抽象装饰者角色,负责对具体构件添加额外功能。
代码举例
对已有的业务逻辑进一步的封装,使其增加额外的功能,如Java中的IO流就使用了装饰者模式,用户在使用的时候,可以任意组装,达到自己想要的效果。 举个栗子,我想吃三明治,首先我需要一根大大的香肠,我喜欢吃奶油,在香肠上面加一点奶油,再放一点蔬菜,最后再用两片面包夹一下,很丰盛的一顿午饭,营养又健康。那我们应该怎么来写代码呢? 首先,我们需要写一个Food类,让其他所有食物都来继承这个类,看代码:
public class Food {
private String food_name;
public Food() {
}
public Food(String food_name) {
this.food_name = food_name;
}
public String make() {
return food_name;
};
}
代码很简单,我就不解释了,然后我们写几个子类继承它:
//面包类
public class Bread extends Food {
private Food basic_food;
public Bread(Food basic_food) {
this.basic_food = basic_food;
}
public String make() {
//加入子类实现的具体逻辑
return basic_food.make()+"+面包";
}
}
//奶油类
public class Cream extends Food {
private Food basic_food;
public Cream(Food basic_food) {
this.basic_food = basic_food;
}
public String make() {
//加入子类实现的具体逻辑
return basic_food.make()+"+奶油";
}
}
//蔬菜类
public class Vegetable extends Food {
private Food basic_food;
public Vegetable(Food basic_food) {
this.basic_food = basic_food;
}
public String make() {
//加入子类实现的具体逻辑
return basic_food.make()+"+蔬菜";
}
}
这几个类都是差不多的,构造方法传入一个Food类型的参数,然后在make方法中加入一些自己的逻辑,如果你还是看不懂为什么这么写,不急,你看看我的Test类是怎么写的,一看你就明白了 。
public class Test {
public static void main(String[] args) {
Food food = new Bread(new Vegetable(new Cream(new Food("香肠"))));
System.out.println(food.make());
}
}
如果用继承去实现的话,会产生什么样的结果呢?
首先,肯定是需要创建一个Food类,然后去创建Food类的子类叫香肠奶油蔬菜三明治,但是如果我每天都不想吃同一种菜,那么每天都需要创建一个子类去继承Food类,这样下去肯定是会产生子类爆炸的。而利用装饰者模式,比如我个人就偏爱吃蔬菜、奶油、鸡蛋、面包等这几个具体的类,那么我们只需要对这几种类进行继承或者实现即可,而不用单独去一一创建组合的子类,具体吃啥则有我们自己对基本food进行自由装饰。