设计模式 | 装饰者模式

知识点八: 装饰者模式


一、概述

装饰器模式(Decorator Pattern)又叫包装模式,允许向一个现有的对象添加新的功能,同时又不改变其结构。它属于23种GOF设计模式的结构型设计模式  ,它是继承关系的一个替换方案

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。


二、优缺点和使用场景

1、优点

  • 装饰者模式可以提供比继承更多的灵活性。
  • 可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
  • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

2、缺点

  • 会产生很多的小对象,增加了系统的复杂性
  • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

3、使用场景

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

三、模式中包含的角色和其职责以及模式实现方式

1、角色

抽象组件(Component)角色:定义一个抽象接口,来规范准备附加功能的类

具体组件(ConcreteComponent)角色:将要被附加功能的类,实现抽象构件角色接口

抽象装饰者(Decorator)角色:持有对具体构件角色的引用并定义与抽象构件角色一致的接口

具体装饰(ConcreteDecorator)角色:实现抽象装饰者角色,负责对具体构件添加额外功能。

2、模式实现方式

  • 定义一个对象接口,可以给这些对象动态地添加职责(Component)。
  • 定义一个对象,可以给这个对象添加一些职责(ConcreteComponent)。
  • 维持一个指向Component实例的引用,并定义一个与Component接口一致的接口(Decorator)。
  • 具体的装饰对象,给内部持有的具体被装饰对象,增加具体的职责(ConcreteDecorator)。

装饰者模式.png


四、在Java中的实现

需求:目前有个会跑的车,需要为该车添加飞的功能;

抽象组件(Car.java)

/**
 * @Description: 抽象组件
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/12 20:32
 */
public interface Car {
    public void show();
}

具体组件(RunCar.java)

/**
 * @Description: 具体组件,定义组件初始功能,原程序
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/13 15:39
 */
public class RunCar implements Car {
    public void run() {
        System.out.println("这车可以跑");
    }

    public void show() {
        this.run();
    }
}

抽象汽车的装饰器(CarDecorator.java)

/**
 * @Description: 抽象汽车的装饰器
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/13 15:33
 */
public abstract class CarDecorator implements Car{
    private Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public CarDecorator(Car car) {
        this.car = car;
    }

    public abstract void show();
}

具体装饰角色(FlyCarDecorator.java)

/**
 * @Description: 具体装饰角色,装饰飞的功能
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/13 15:24
 */
public class FlyCarDecorator extends CarDecorator {

    public FlyCarDecorator(Car car) {
        super(car);
    }

    public void show() {
        this.getCar().show();
        this.fly();
    }

    public void fly(){
        System.out.println("这车会飞");
    }
}

测试(MainClass.java)

/**
 * @Description:
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/12 20:32
 */
public class MainClass {
    public static void main(String[] args) {
        //先实例一辆车
        RunCar car = new RunCar();
        //把这车给飞行装饰器装饰,得到飞行功能
        FlyCarDecorator flyCar = new FlyCarDecorator(car);
        //看效果
        flyCar.show();
    }
}

这时候需要添加功能,车可以游,只需要添加响应的装饰类就好,如:

具体装饰角色(SwimCarDecorator.java)

/**
 * @Description: 具体装饰角色,装饰游的功能
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/13 16:00
 */
public class SwimCarDecorator extends CarDecorator implements Car {
    public SwimCarDecorator(Car car) {
        super(car);
    }

    public void show() {
        this.getCar().show();
        this.Swim();
    }

    //要添加的功能
    public void Swim(){
        System.out.println("这车可以游");
    }
}

测试(MainClass.java)

/**
 * @Description:
 * @Author: Ling.D.S
 * @Date: Created in 2018/11/12 20:32
 */
public class MainClass {
    public static void main(String[] args) {
        //先实例一辆车
        RunCar car = new RunCar();
        //把这车给飞行装饰器装饰,得到飞行功能
        FlyCarDecorator flyCar = new FlyCarDecorator(car);
        //看效果
        flyCar.show();

        System.out.println("========================");

        //添加功能
        SwimCarDecorator swimCar = new SwimCarDecorator(flyCar);
        swimCar.show();
    }
}

转载请注明原地址,宋德凌的博客:http://CoderOfSong.github.io 谢谢!

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦