23种设计模式系列目录
23种设计模式之单例模式(Singleton Pattern)
23种设计模式之适配器模式(Adapter Pattern)
23种设计模式之抽象工厂模式(Abstract Factory Pattern)
23种设计模式之装饰器模式(Decorator Pattern)
--------------------------------------------------------------------------------------------------------------------------
读完本篇文章将会了解以下问题
1. 装饰器模式定义
2. 装饰器模式代码实现
3. 装饰器模式的优缺点分析
4. 装饰器模式使用场景
--------------------------------------------------------------------------------------------------------------------------
1. 装饰器模式定义
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构,是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时又避免了类型体系的快速膨胀。
目的:避免因为使用继承的方式扩展类功能时导致的子类膨胀问题。
何时使用:不想因为引入静态特征而增加很多子类的情况。
如何解决:将具体功能职责划分,同时继承装饰者模式。
关键代码:1、Component 类充当抽象角色,不应该具体实现。
2、修饰类引用和继承 Component 类,具体扩展类重写父类方法。
标准类图:
- Component:统一接口,也是装饰类和被装饰类的基本类型。
- ConcreteComponent:具体实现类,也是被装饰类。
- Decorator:装饰类,实现Component接口同时在内部维护了一个ConcreteComponent的实例,并可以通过构造函数初始化。
- ConcreteDecorator:具体的装饰产品类,每一种装饰产品都具有特定的装饰效果。
2. 装饰器模式代码实现
举个例子,比如有个人叫刘小白,他可能善良,可能性感,可能会跑,也可能会跳。如果不引入设计模式,我们可能写一个名叫刘小白的类,然后写一个善良的刘小白的类,性感的刘小白的类,会跑的刘小白的类,会跳的刘小白的类,让这四个类继承自刘小白的基类。那么问题来了,我要是想要一个善良又能跑的刘小白呢?再去写一个善良又能跑的刘小白类。如果再多一个“可爱”的属性呢,这得要写多少个类啊。。。所以就需要用到装饰器模式,上类图:
为什么比上面的标准类图还复杂我们下面再说,People:相当于Component,统一接口,在这里作为一个标记接口
public interface People {
}
Liuxiabai:是个人名,为被装饰类,也没写啥内容
public class Liuxiabai implements People{
}
Decorator:具体装饰类的声明类
public class Decorator implements People{
}
Appearance:外观类,继承自装饰类的抽象类
abstract class Appearance extends Decorator{
public Liuxiabai liuxiabai;
public Appearance(Liuxiabai liuxiabai){
this.liuxiabai = liuxiabai;
}
}
Behavior:行为类,继承自装饰类的抽象类
abstract class Behavior extends Decorator{
public Appearance liuxiabai;
public Behavior(Appearance liuxiabai){
this.liuxiabai = liuxiabai;
}
}
GoodLiuxiaobai:善良的刘小白类,具体的装饰类
public class GoodLiuxiaobai extends Appearance{
public GoodLiuxiaobai(Liuxiabai liuxiabai) {
super(liuxiabai);
}
public void Good(){
System.out.println("Liuxiaobai is good!");
}
}
SexyLiuxiaobai:性感的刘小白类,具体的装饰类
public class SexyLiuxiaobai extends Appearance{
public SexyLiuxiaobai(Liuxiabai liuxiabai) {
super(liuxiabai);
}
public void Sexy(){
System.out.println("Liuxiaobai is sexy!");
}
}
JumpLiuxiaobai:能跳的刘小白类,具体的装饰类
public class JumpLiuxiaobai extends Behavior{
public JumpLiuxiaobai(Appearance liuxiabai) {
super(liuxiabai);
}
public void Jump(){
System.out.println("Liuxiaobai is Jumping!");
}
}
RunLiuxiaobai:能跑的刘小白类,具体的装饰类
public class RunLiuxiaobai extends Behavior{
public RunLiuxiaobai(Appearance liuxiabai) {
super(liuxiabai);
}
public void Run(){
System.out.println("Liuxiaobai is Running!");
}
}
上面写了一大堆乱七八糟的估计大家都懵了,没关系,下面让我们来体验一下装饰器模式的魅力大家就理解了,如果我们只想要一个纯的刘小白,那么我们可以:
new Liuxiabai();
如果想要一个善良的刘小白呢?
new GoodLiuxiaobai(new Liuxiabai());
如果想要一个性感的刘小白呢?
new SexyLiuxiaobai(new Liuxiabai());
如果想要一个能跑又性感的刘小白呢?
new RunLiuxiaobai(new SexyLiuxiaobai(new Liuxiabai()));
为什么上图比标准类图还复杂呢,童鞋们可以看到在Behavior(行为类)里保存的实例对象是Appearance(外观类)的对象:
这是为了产生上面最后那种链式适配的效果,在JDK的InputStream中也是这样的,这个我们下面再说。
3. 装饰器模式的优缺点分析
装饰器模式的优点:
1、相对于继承,灵活性更强,装饰器将功能切分成一个个独立的装饰器,在运行期间可以根据需要动态添加功能,甚至可以对新功能进行自由组合。
2、相对于继承,扩展性更强,当有新功能需要添加的时候,只需要添加新的装饰器实现类,然后通过组合的方式添加这个新的装饰器,无需修改已有代码,符合开闭原则。
装饰器模式的缺点:
1、多层装饰比较复杂(引自菜鸟教程,但我感觉不算是缺点,也没感觉到有多复杂。。。)
4. 装饰器模式使用场景
1、JDK中IO输入输出流的设计
new BufferedReader(new InputStreamReader(new FileInputStream("c:\\test")));
2、Servlet API中提供了一个request对象的装饰器模式实现类HttpServletRequsetWrapper,增强了requset对象的功能,有兴趣的同学可以去翻一下源码,这里我就不带大家找啦。
3、MyBatis的缓存组件,这个具体可以看下我这篇博文:啃下MyBatis源码 - org.apache.ibatis.cache包源码分析