Java设计模式之装饰器模式

相关知识

装饰器模式的作用;
汽车接口和不同的汽车的实现;
装饰器;
执行喷漆操作的装饰器类;
主函数。

装饰器模式的作用

试想有这样一种场景,汽车有很多的种类,它们都具有驾驶的功能,不论是大众、蔚来,还是解放、拖拉机,它们的驾驶功能的实现方式不一定相同,有汽油驱动的、电力驱动的、柴油驱动的。

现在我们要在汽车驾驶之前,给汽车进行装饰,比如喷漆。对不同的汽车,喷漆的方式都是相同的。从程序的角度来说,喷漆的功能要写在汽车驾驶功能 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 动作。

看下运行结果:
在这里插入图片描述

图 运行结果

不论是哪种汽车,驾驶之前,都会先被喷漆,符合预期。

总结
看了这个例子,我们可以总结下装饰器模式的核心要素:

装饰器中,需要有一个被装饰的目标对象(比如上例中的汽车)作为成员变量;
装饰器类,和被装饰的目标对象实现同一个接口;
装饰器类,在这个同一接口的里面,先调用装饰方法(比如喷漆),然后再通过目标对象成员变量执行本来的功能(比如驾驶);

简单来说,装饰器类就是给目前对象类套了一个壳子。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ac果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值