走穿23种设计模式-7装饰模式详解
装饰模式说是挺好说的,无非就是給一个类添加一些方法做装饰,但是要真正理解装饰模式并且知道它和其他模式的一些区别还是有点难理解的,本文就带你去学习一下。
一.装饰模式现实场景:装饰新车
王小华从奔驰4S店购买一辆E260车,但打算直接送给女友,不过它考虑到女朋友方向感不是太好,而且很喜欢Hello Kitty ,所以他打算把刚买的车装饰一下再送过去。他在4S店安装了一个GPS导航系统和行车记录仪,然后又买了一套Hello Kitty坐垫和贴纸,給车做了一个“美容”,让新车看起来比原来更加温馨浪漫,除此之外他还在车后视玻璃上贴上了一张警示语,表明司机是新手,提醒车辆避让。
从上面场景,可以看到装饰模式就是給一个对象添加属性、方法,让这个类功能、样式多样化,但是又有什么优点呢?后面看吧。
二.装饰模式的定义
动态給一个对象添加一些额外的职责。
就增加功能来说,装饰模式相比于代理模式生成子类跟为灵活。
怎么理解这里的灵活呢?
三.装饰模式的类图:
四.装饰模式4种角色:
1.抽象角色Component:
该角色用于规范需要装饰的原始对象
2.具体构件角色(Concrete Component):
该角色实现抽象构件接口,定义一个需要装饰的原始对象
3.装饰角色(Decorator)
该角色持有一个构件对象的实例,并定义一个与抽象构件接口一致的接口。
4.具体装饰角色(Concrete Decorator)
该角色负责对构件对象进行修饰。
五.装饰模式的理解
其实装饰模式关键也是对象的持有,如果看我上一篇代理模式能够理解的话,对这个对象的持有的理念应该是更加深刻的。代理模式也是把操作对象传入代理类中,调用代理类来給实际对象做事情.
从装饰模式的定义中说到:給一个对象添加额外的职责。
这里把职责定义一个接口,并定义需要的方法,让另一个装饰角色来继承这个接口,并持有需要装饰的对象,这样就能得到一个经过装饰的对象。
并且这里的职责接口定义是不需要知道具体对象的,他也是可以针对其他相关的对象来进行修饰。把你需要装饰的对象传进去就可以了。
六.装饰模式的优缺点
1.优点
(1)装饰类和被装饰类可以独立发展,而不会互相耦合
(2)装饰模式的继承关系的一个替代方案.装饰类Decorator装饰多层,返回的对象都是Component(抽象构件),实际上实例化的是具体构件,也就是要装饰的对象!
(3)装饰模式可以动态地扩展一个实现类的功能.
2.缺点
多层装饰比较复杂
七.装饰模式的使用场景
1.需要扩展一个类的功能,或給一个类添加附加功能.当然最好是給多个相关类都添加这个功能的场景.
2.需要动态給一个对象增加功能,这些功能可以动态地撤销.
3.需要为一批类进行改装或加装功能.
装饰模式是对继承功能的有力补充.单纯使用继承时,在某些情况虾会增加很多子类,而且灵活性差,也不容易维护.装饰模式可以替代继承,解决膨胀的问题,如java基础类库中的输入、输出流相关的类使用了装饰模式:比如把一个字节流放入文件封装类中,可以得到一个文件流,对文件进行相关操作。
八.装饰模式的一个简单实例
这里拿上面现实场景买车并装饰设计成代码.
这个实例的代码不一定很符合这个模式的理解,但是意思上的这样的.
实例类图
这个类图完全是结合上面模式框架结合具体代码设计出来的.
这里可以看到装饰角色中持有抽象构件,但是实例化的对象是具体构件,所有装饰角色最后持有的还是具体构件.
1.定义汽车接口ICar
package p7_decorator;
/**
* 汽车接口
*/
public interface ICar {
//车的装配
void show();
}
2.实际要装饰的对象奔驰E260
package p7_decorator;
/**
*奔驰E260,装饰对象(裸车,需要装饰)
*/
public class BenzE260 implements ICar {
@Override
public void show() {
System.out.print("奔驰E260车,无导航仪,无行车记录仪,内饰原装。。。");
}
}
3.汽车修饰抽象类CarDecorator
package p7_decorator;
/**
* 汽车装饰类(抽象装饰)
* 持有装饰实例对象
*/
public abstract class CarDecorator implements ICar {
private ICar car;//接口类,但是实例对象是子类,就是具体构件
public CarDecorator(ICar car) {
this.car = car;
}
public void show() {
this.car.show();
}
}
4.汽车修饰实现类ConcreteCarDecorator
package p7_decorator;
/**
* 具体汽车装饰类
*/
public class ConcreteCarDecorator extends CarDecorator {
public ConcreteCarDecorator(ICar car) {
super(car);
}
//給车安装行车记录仪
private void setGrapher() {
System.out.println("安装高清大容量带夜视的行车记录仪。。。。。。");
}
//給车安装GPS设备
private void setGps() {
System.out.println("安装最顶级的GPS定位导航仪。。。。。。");
}
//給车铺上坐垫并贴上警示语
private void setCushion() {
System.out.println("铺上HelloKitty的坐垫,然后在后车玻璃贴上警示语便签,标明司机是新手。。。。。。");
}
//重写show方法
public void show() {
super.show();
//装饰的方法
setGrapher();
setGrapher();
setGps();
setCushion();
}
}
5.测试类DecoratorDemo
package p7_decorator;
/**
* 测试类
*/
public class DecoratorDemo {
public static void main(String[] args){
ICar car=new BenzE260();//多态,子类的实例
CarDecorator carDecorator=new ConcreteCarDecorator(car);//多态,子类的实例
carDecorator.show();//装饰者返回的数据(对象)
}
}
上面代码运行结果:
装饰者就介绍到这里。
无论是前面介绍过的代理模式还是装饰者模式都是在模式类中持有具体操作对象。
有些装饰模式,在装饰完一个类后返回的还是这个类的对象,你还可以继续进行装饰,这个大家在SDK中应该是见过不少的了。
大家也可以看看,我之前写的几种模式的详解:
代理模式:http://blog.csdn.net/wenzhi20102321/article/details/78209493
创建型模式详解:http://blog.csdn.net/wenzhi20102321/article/details/78175558
原型模式:http://blog.csdn.net/wenzhi20102321/article/details/78167984
建造者模式:http://blog.csdn.net/wenzhi20102321/article/details/78163855
抽象工厂模式:http://blog.csdn.net/wenzhi20102321/article/details/78153437
工厂方法模式:http://blog.csdn.net/wenzhi20102321/article/details/78129065
可以仔细对比一下工厂方法模式和抽象工厂模式,看看概念,看看类图,看看代码,就会明白了。
单例模式:http://blog.csdn.net/wenzhi20102321/article/details/77882203
java 23种设计模式介绍:http://blog.csdn.net/wenzhi20102321/article/details/54601909