装饰模式——Decorator

案例展示——Decorator怎么用?

 现在有这样一种场景:关于二手车我们都不会陌生,或多或少我们都会有接触。那你有没有想过,如何才能把一辆二手车卖出好的价钱呢?是直接和买主摊牌二手车的所有性能参数,还是会适当的加以修饰一下来获得一个好的价位呢?诚然,所谓商场之道,诚信至上,我们当然需要诚实的与买主说清楚二手车的各种参数,但是在商言商,我想些许修饰也是不过分的,下面是一家二手车4S店卖二手车的一个类图设计:

装饰模式——Decorator

类图元素分析:

  • SHCar:二手车抽象类,里面有两个基本的方法,show()方法用于向用户展示二手车的基本参数;order()方法为用户下订单。

  • SHBaomaCar:具体的二手车类型

  • Decorator:一个抽象的装饰类,它会对每辆二手车进行装饰

  • PowerEngineDecorator:具体的装饰类,继承了Decorator,用于装饰二手车的引擎

  • FastSpeedDecorator:具体的装饰类,继承了Decorator,用于装饰二手车的速度

下面是具体的代码展示:

// 抽象车类
public abstract class SHCar {
    // 给客户展示二手车的基本信息
    public abstract void show();
    // 用户下订单
    public abstract void order(String name);
}

// 具体的类型
public class SHBaomaCar extends SHCar{
    // 展示一下二手宝马车
    public void show() {
        System.out.println("型号:宝马X6");
        System.out.println("颜色:宝石蓝");
        System.out.println("发动机:动力好");
        System.out.println("推荐:性价比高,值得拥有");
    }

    // 用户下订单
    public void order(String name) {
        System.out.println("我是 " + name + ",这辆车我要了!");
    }
}

// 抽象装饰器
public abstract class Decorator extends SHCar{
    // 那种类型的二手车:宝马,奔驰,奥迪,法拉利....
    private SHCar sc;

    // 构造函数,传入二手车
    public Decorator(SHCar sc) {
        this.sc = sc;
    }

    // 查看二手车的具体信息
    public void show() {
        this.sc.show();
    }

    // 用户下订单
    public void order(String name) {
        this.sc.order(name);
    }
}

// 引擎装饰器
public class PowerEngineDecorator extends Decorator{
    // 构造函数
    public PowerEngineDecorator(SHCar sc) {
        super(sc);
    }

    // 说说这辆车的强大的引擎
    private void showEngine() {
        System.out.println("====进口引擎,动力杆杆的!!!====");
    }

    // 在向用户展示之前先给他说一下
    @Override
    public void show() {
        this.showEngine();
        super.show();
    }
}

// 速度装饰器
public class FastSpeedDecorator extends Decorator {
    // 构造函数
    public FastSpeedDecorator(SHCar sc) {
        super(sc);
    }
    
    // 说说这辆车的速度:百米加速3秒!
    private void showSpeed() {
        System.out.println("=====百米加速3秒!!!=====");
    }

    // 在展示之后和用户说一下,增加吸引力
    @Override
    public void show() {
        super.show();
        this.showSpeed();
    }
}

// 客户买车
public class Client {
    public static void main(String[] args) {
        // 没有修饰的原装车
        SHCar sc = new SHBaomaCar();
        // 修饰一下:强大的引擎
        sc = new PowerEngineDecorator(sc);
        // 强调一下:超快的速度
        sc = new FastSpeedDecorator(sc);
        // 展示
        sc.show();
        // 用户很开心,下单!
        sc.order("张三");
    }
}

// 运行结果如下:
====进口引擎,动力杆杆的!!!====
型号:宝马X6
颜色:宝石蓝
发动机:动力好
推荐:性价比高,值得拥有
=====百米加速3秒!!!=====
我是 张三,这辆车我要了!

 上面的例子中使用的就是装饰模式,通过一个抽象的装饰器得到它要装饰的类型,然后交给具体的装饰类型去装饰,这样在没有改变二手车基本参数的情况下,使其给客户的观感更好,人家自然很高兴就下单了。

深入分析——Decorator是什么?

Decorator的定义

定义: 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。下面是装饰模式的通用类图:

装饰模式——Decorator

  • Conponent组建:一个接口或者抽象类,定义最核心的对象,如二手车

  • ConcreateComponent组建:具体的构建,被装饰的对象

  • Decorator组建:装饰者

  • ConcreateDecorator:具体的装饰者

下面是具体代码

// 抽象构建
public abstract class Component {
    // 抽象方法
    public abstract void operate();
}

// 具体构建
public class ConcreateComponent extends Component {
    // 具体实现
    public void operate() {
        // 业务逻辑
    }
}

// 抽象装饰器
public abstract class Decorator extends Component{
    // 修饰哪个组建
    private Component component = null;
    // 通过构造函数传递被修饰者
    public Decorator(Component component) {
        this.component = component;
    }
    // 委托给被修饰者执行
    @Override
    public void operate() {
        this.component.operate();
    }
}

// 具体的装饰器
public class ConcreateDecorator1 extends Decorator {
    // 传递被修饰者
    public ConcreateDecorator1(Component component) {
        super(component);
    }
    // 定义自己的修饰方法
    private void method1() {
        // 修饰
    }
    // 重写父类的operate()方法
    public void operate() {
        this.method1();
        super.operate();
    }
}

// 具体的装饰器
public class ConcreateDecorator2 extends Decorator {
    // 传递被修饰者
    public ConcreateDecorator2(Component component) {
        super(component);
    }
    // 定义自己的修饰方法
    private void method2() {
        // 修饰
    }
    // 重写父类的operate()方法
    public void operate() {
        super.operate();
        this.method2();
    }
}

// 场景类
public class Client {
    public static void main(String[] args) {
        Component component = new ConcreateComponent();
        // 第一次修饰
        component = new ConcreateDecorator1(component);
        // 第二次修饰
        component = new ConcreateDecorator2(component);
        // 运行
        component.operate();
    }
}
Decorator的优点
  • 装饰类和被装饰类可以独立发展,而不会相互耦合

  • 装饰模式是继承关系的一个替代方案

  • 装饰模式可以动态的扩展一个实现类的功能

Decorator的缺点
  • 装饰类太多会增加复杂性

  • 会产生很多小对象,增加系统的复杂性

  • 虽然比继承更加灵活,当时也意味着比继承更加容易出错。在出现错误后,由于多层装饰,排错很困难,需要逐级排查,较为繁琐

Decorator的应用场景

  • 需要扩张一个类的功能或给一个类增加附加功能

  • 需要动态的给一个对象增加功能,这些功能可以再动态的撤销

  • 需要为一批兄弟类改装或加装功能

参考

《设计模式之禅》