装饰者设计模式(Decorator)
一、场景还原
假设我们正在公司中工作,有一天产品提出了一个需求:我们要造车,车拥有跑、停车,两个功能,此时我们会发现这样的需求太简单了。我定义个Car类然后再写两个方法run(跑),stop(停车)不就ojbk了太简单了(如下图)
可是过了一段时间产品有来了,你这个车功能不满足我的要求了,我要让这个车五秒启动,火箭式飞驰。这时我们又该想了,不就是改代码吗,我就修改run的功能(syso(“五秒启动,火箭式飞驰”))。可是过了一段时间,这产品脑袋抽风了?又来需求了,我想要原来的功能(syso(“车在跑”))此时我们心情真是一万只xxx哈哈。我们心情经历如下:
二、分析
上面的一些经历也体现出我们设计代码中的好多弊端:违反了面向对象程序设计的开闭原则
试想我们在公司中写好的代码功能经过测试了,我们是不允许你以后再修改的,对于已经定好的功能点,对于以后的修改应该是出于封闭的。
所以我们迫切需要一种解决思路。在不修改原来的功能的情况下再拓展装饰这个功能。所以我们想到的我们常用的继承,但是继承也有弊端的。
- 继承的好处:子类可以拿到父类东西 且可以修改。
- 继承的弊端:需要父类(父子之间耦合)
所以我们还是想拥有更加灵活的代码设计,此时装饰者设计模式就可以做到。
三、装饰者
装饰者模式通过组合的方式扩展对象的特性,这种方式允许我们在任何时候对对象的功能进行扩展甚至是运行时扩展,而若我们用继承来完成对类的扩展则只能在编译阶段实现,所以在某些时候装饰者模式比继承(inheritance)要更加灵活。
使用装饰者:(实现步骤)
1 装饰者 和被装饰者同时实现同一个接口 或者继承同一个类
2 装饰者中要有被装饰着的引用
3 对需要增强的方发进行增强()
4 对不需要增强的方法调用原来的方法()
使用如上栗子我们结合装饰者简单的实现步骤画下uml图:
如上图:我们对变化的run这个需求装饰,对不变的stop方法我们是调用即可。
(来个新的需求,我们创建新的类装饰下就完事了)
1、代码实现
接口:Icar
package pattern_decorator;
/**
* Create by SunnyDay on 2019/04/07
*/
public interface Icar {
void run();
void stop();
}
原始类:car
package pattern_decorator;
/**
* Create by SunnyDay on 2019/04/07
* 原始类
*/
public class Car implements Icar {
@Override
public void run() {
System.out.println("车 在跑");
}
@Override
public void stop() {
System.out.println("刹车!!!");
}
}
装饰类:CarWrap
package pattern_decorator;
/**
* Create by SunnyDay on 2019/04/07
*/
public class CarWrap implements Icar {
private Icar icar;// 对象引用类型 采用面向父类编程思想(可以修饰任意车 通用)
public CarWrap(Icar car) {
this.icar = car;
}
/**
* /对需要增强的进行改造
* */
@Override
public void run() {
System.out.println("我的宝马 5 秒启动!!! 6的飞起");
}
/**
* 对不需要增强的方法调用原来的方法()
* */
@Override
public void stop() {
icar.stop();
}
}
简单测试:
package pattern_decorator;
/**
* Create by SunnyDay on 2019/04/07
*/
public class Test {
public static void main(String[] args){
// 未进行修饰
Car car = new Car();
car.run();
car.stop();
//进行修饰
CarWrap icar = new CarWrap(car);
icar.run();
icar.stop();
}
}
/*
log:
车 在跑
刹车!!!
我的宝马 5 秒启动!!! 6的飞起
刹车!!!
*/
四、优缺点
- 优点:动态地为对象增加新的功能或者撤销功能(继承就不能做到这一点)
- 缺点:会产生过多的相似的对象
参考文章:详细讲解装饰者模式和继承之间的关系和优劣(讲道理这事儿,不怕过 就怕不够)
五 小结:
本篇的总结只是以一个贴切的例子概述了使用,以及简单的介绍了下优缺点,写这篇总结加深一下记忆,以及理解吧。