相关知识
装饰器模式的作用;
汽车接口和不同的汽车的实现;
装饰器;
执行喷漆操作的装饰器类;
主函数。
装饰器模式的作用
试想有这样一种场景,汽车有很多的种类,它们都具有驾驶的功能,不论是大众、蔚来,还是解放、拖拉机,它们的驾驶功能的实现方式不一定相同,有汽油驱动的、电力驱动的、柴油驱动的。
现在我们要在汽车驾驶之前,给汽车进行装饰,比如喷漆。对不同的汽车,喷漆的方式都是相同的。从程序的角度来说,喷漆的功能要写在汽车驾驶功能 drive 的里面。我们有必要把每一种汽车的 drive 函数都重写吗?
不现实且没必要,那怎么做到只写一遍?
这就需要用到装饰器模式,我们提供一个装饰器类,把汽车作为这个类的成员变量。同时,这个类实现了汽车类统一的接口 Car。那么它自然也要实现驾驶的功能 drive,我们在 drive 的实现代码中,先调用喷漆的程序,再调用汽车成员变量的驾驶功能。就实现了,对所有的汽车,驾驶之前,先统一喷漆。
我们先看下这个例子怎么实现,最后再总结下装饰器类的核心原理。
汽车接口和不同的汽车的实现
我们需要给汽车提供一个统一的接口 Car,如下:
/**
- 汽车接口
*/
public interface Car {
//驾驶
void drive();
}
不同的汽车种类,都需要去实现驾驶功能 drive。
大众、宝马两款汽车需要实现驾驶功能,如下:
/**
- 大众汽车
*/
public class DaZhongCar implements Car{
/**
* 实现驾驶功能
*/
@Override
public void drive() {
System.out.println("驾驶大众汽车");
}
}
宝马汽车:
/**
- 宝马汽车
*/
public class BaoMaCar implements Car{
/**
* 实现驾驶功能
*/
@Override
public void drive() {
System.out.println("驾驶宝马汽车");
}
}
装饰器
装饰器,要在汽车使用驾驶功能之前,提供一个装饰功能,由于装饰功能可能有多种,比如喷漆、贴膜等等,我们抽象出一个公共的装饰类,然后不同的装饰功能继承自这个抽象类。
公共的装饰类如下:
/**
- 适配器抽象类
*/
public abstract class Decoration implements Car{
//将被装饰的类作为成员变量
protected Car car;
//构造函数
public Decoration(Car car) {
this.car = car;
}
//实现驾驶功能
@Override
public void drive() {
car.drive();
}
}
这个类,和具体的汽车类一样,也需要实现 Car 接口中的驾驶功能 drive。
不同的是,装饰器本身是不具备驾驶能力的,所以它需要调用内部的汽车变量 car 来执行驾驶的动作
执行喷漆操作的装饰器类
装饰有很多种类,看下其中的一种:喷漆:
/**
- 给汽车喷漆
*/
public class PaintDecoration extends Decoration{
//构造函数
public PaintDecoration(Car car) {
super(car);
}
//驾驶汽车
@Override
public void drive() {
//给汽车装饰
paintCar();
//驾驶汽车
car.drive();
}
//给汽车喷漆(装饰的一种)
private void paintCar() {
System.out.println("给汽车喷漆");
}
}
喷漆类中,在汽车驾驶功能 drive 中,会先调用 paintCar 来给汽车喷漆,之后才会调用 drive 去实现汽车的驾驶功能。
主函数
最后,看下主函数中怎么使用装饰器的:
/**
- 主函数类
*/
public class Main {
/**
* 主函数
* @param args
*/
public static void main(String[] args) {
//实例化一辆大众汽车
Car dazhong = new DaZhongCar();
//实例化一辆宝马汽车
Car baoma = new BaoMaCar();
//装饰大众汽车
Decoration dazhongDecoration = new PaintDecoration(dazhong);
//装饰后,驾驶大众汽车
dazhongDecoration.drive();
//装饰宝马汽车
Decoration baomaDecoration = new PaintDecoration(baoma);
//装饰后,驾驶宝马汽车
baomaDecoration.drive();
}
}
先实例化不同种类的汽车,然后将这些汽车作为入参,塞入喷漆类的构造函数中,这样它们就是喷漆类的成员变量 car 了,当喷漆类执行 drive 函数时,就会先执行统一的喷漆动作,然后调用不同汽车的 drive 动作。
看下运行结果:
图 运行结果
不论是哪种汽车,驾驶之前,都会先被喷漆,符合预期。
总结
看了这个例子,我们可以总结下装饰器模式的核心要素:
装饰器中,需要有一个被装饰的目标对象(比如上例中的汽车)作为成员变量;
装饰器类,和被装饰的目标对象实现同一个接口;
装饰器类,在这个同一接口的里面,先调用装饰方法(比如喷漆),然后再通过目标对象成员变量执行本来的功能(比如驾驶);
简单来说,装饰器类就是给目前对象类套了一个壳子。