装饰模式(也叫包装模式)
//汽车接口 public interface Car { //驾驶 void drive(); }
//轿车类 public class Bus implements Car { @Override public void drive() { System.out.println("驾驶轿车"); } }
上面我们已经拥有了一个接口还有一个默认实现。包装模式是做的:
首先我们弄一个装饰器,它实现了接口,以组合的方式接收我们的默认实现类。
/** * 装饰器(抽象类) */ public abstract class CarDecorate implements Car{ // 以组合的方式来获取默认实现类 private Car car; public CarDecorate(Car car) { this.car = car; } @Override public void drive() { car.drive(); } }
有了装饰器以后,我们的扩展都可以以装饰器为基础进行扩展,继承装饰器来扩展就好了!
我们想要在开车之前听音乐:
/** * 继承着装饰器来扩展 */ public class MusicCar extends CarDecorate { public MusicCar(Car car) { super(car); } // 定义想要扩展的功能 public void listenMusic() { System.out.println("开车听音乐"); } //重写驾驶的方法 @Override public void drive() { //开车之前听歌 this.listenMusic(); super.drive(); } }
现在我也想在打开音乐后打开汽车的地图导航,于是我们也继承装饰类来扩展:
/** * 继承着装饰器来扩展 */ public class MapCar extends CarDecorate { public MapCar(Car car) { super(car); } //开车后打开地图导航 public void map(){ System.out.println("开车后打开地图导航"); } @Override public void drive() { super.drive(); this.map(); } }
可以来测试一下:
//测试类 public class Test { public static void main(String[] args) { //创建最原始的核心类 Car car = new Bus(); //装饰成开车前听音乐,第一次增强 car = new MusicCar(car); //装饰成开车后打开导航,第二次增强 car = new MapCar(car); car.drive(); //简写 Car c = new MusicCar(new MapCar(new Bus())); //有没有发现很像IO的写法,其实IO就是装饰模式实现的 c.drive(); } }
输出结果:
优点:
-
装饰类和被装饰类是可以独立的,低耦合的。互相都不用知道对方的存在
-
装饰模式是继承的一种替代方案,无论包装多少层,返回的对象都是is-a的关系(上面的例子:包装完还是Phone类型)。
-
实现动态扩展,只要继承了装饰器就可以动态扩展想要的功能了。
缺点:
-
多层装饰是比较复杂的,提高了系统的复杂度。不利于我们调试~
注:其实装饰模式或者继承或者代理模式都是对对象的增强