一、装饰者模式
1.概念定义
所谓装饰者模式就是动态的给一个对象添加额外的功能,它比生成子类来得更加灵活。
2.应用场景
装饰者模式多半应用于二次开发的过程中,当你需要对已有得系统添加新的功能,而又无法获得源码且不能使用继承得情况下(要扩展得功能类里边含有final关键字),这时候就需要使用到装饰者设计模式来解决问题。
其实即使我们有方法能够获取到源码,基本上我们也不会去修改源码,因为修改源码所引发得问题无异于一场灾难,而且大大的违法了开放–封闭的设计原则(所谓开放封闭原则就是开放修改功能且封闭修改)。
使用装饰者模式也要满足一个前提:需要获取到被装饰类所实现的所有接口。
装饰者模式举例
需求:有一套无人车驾驶汽车的开发接口,里面定义了启动汽车、停止汽车的方法,然后Google公司实现了这个接口开发出了无人驾驶汽车,后来随着时代的发展,这个接口的功能已经不能够满足我们的需求了,现Google公司需要在启动汽车之前先自动查询天气预报以及车辆自身安全检查的的情况,代码如下:
接口Car
package com.gzgs.demo;
public interface Car {
public void start();
public void stop();
}
Google一代汽车
package com.gzgs.demo;
public class GoogleCar_1 implements Car {
@Override
public void start() {
System.out.println("汽车启动....");
}
@Override
public void stop() {
System.out.println("汽车停止....");
}
}
Google二代汽车
package com.gzgs.demo;
public class GoogleCar_1 implements Car {
@Override
public void start() {
System.out.println("汽车启动....");
}
@Override
public void stop() {
System.out.println("汽车停止....");
}
}
主类
package com.gzgs.demo;
public class demo {
public static void main(String[] args) {
GoogleCar_2 googleCar=new GoogleCar_2(new GoogleCar_1());
googleCar.start();
googleCar.stop();
}
}
运行结果
通过这个案例应该可以很好的理解装饰者模式,下面再深入了解一下这个模式。
装饰者模式与继承
why 装饰者 no 继承?
在上面这个例子中,其实要想实现这个新的功能用继承的方式也能够实现,继承GoogleCar_1这个类之后直接重写父类中的start()方法,可以轻而易举的实现扩展功能,那为什么不使用继承的方式呢? 其实在这个小例子中是可以使用继承的,甚至会比用装饰者模式来得方便,但是在实际的开发中,继承就会显得比较笨重,不够灵活,使用装饰者模式的话我们可以根据需要直接去调用被装饰类中的原生方法,而使用继承就得去重写方法,这样会显得比较笨重。
装饰者模式的本质实际上就是动态组合。
在面向对象的设计中,有一条基本的规则就是“尽量使用对象组合,而不是对象继承”来扩展和复用功能。装饰模式的思考起点就是这个规则
什么是对象组合? 下面例子选自《研磨设计模式》一书的装饰者模式章节
直接举例来说吧,假若有一个对象 A,实现了一个 a1 的方法,而 C1 对象想要来扩展 A 的功能,给它增加一个 c11 的方法,那么一个方案是继承,
A 对象示例代码如下:
public class A {
public void a1(){
System.out.println("now in A.a1");
}
}
C1 对象示例代码如下:
public class C1 extends A{
public void c11(){
System.out.println("now in C1.c11");
}
}
另外一个方案就是使用对象组合,怎么组合呢?就是在 C1 对象中不再继承 A 对象了,而是去组合使用 A 对象的实例,通过转调 A 对象的功能来实现 A 对象已有的功能。
写个新的对象 C2 来示范,示例代码如下:
public class C2 {
/**
* 创建A对象的实例
*/
private A a = new A();
public void a1(){
//转调A对象的功能
a.a1();
}
public void c11(){
System.out.println("now in C2.c11");
}
}
这样相比可以看出对象组合会更加灵活且适用于实际的开发。
装饰者模式的优缺点
比继承更灵活
从为对象添加功能的角度来看,装饰模式比继承更灵活。继承是静态的,而且一旦继承所有子类都有一样的功能。而装饰模式采用把功能分离到每个装饰器当中,然后通过对象组合的方式,在运行时动态地组合功能,每个被装饰的对象最终有哪些功能,是由运行期动态组合的功能来决定的。
更容易复用功能
装饰模式把一系列复杂的功能分散到每个装饰器当中,一般一个装饰器只实现一个功能,使实现装饰器变得简单,更重要的是这样有利于装饰器功能的复用,可以给一个对象增加多个同样的装饰器,也可以把一个装饰器用来装饰不同的对象,从而实现复用装饰器的功能。
简化高层定义
装饰模式可以通过组合装饰器的方式,为对象增添任意多的功能。因此在进行高层定义的时候,不用把所有的功能都定义出来,而是定义最基本的就可以了,可以在需要使用的时候,组合相应的装饰器来完成所需的功能。
装饰模式的缺点是:会产生很多细粒度对象。
前面说了,装饰模式是把一系列复杂的功能,分散到每个装饰器当中,一般一个装饰器只实现一个功能,这样会产生很多细粒度的对象,而且功能越复杂,需要的细粒度对象越多。