装饰器模式

在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰模式来实现。

一、装饰器模式

1、装饰器模式的定义

装饰器模式(Decorator Pattern),又叫作包装器模式(Wrapper Pattern):

指在不改变原有对象结构的基础情况下,动态地给该对象增加一些额外功能的职责。装饰器模式相比生成子类更加灵活。它属于对象结构型模式。

装饰模式和代理模式的功能是雷同的,两者区别是:

  • 装饰器模式强调自身功能的扩展,是代理模式的一个特殊应用。
  • 代理模式强调对代理过程的控制。
2、装饰器模式的结构

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。
如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。

下面来分析其基本结构和实现方法。

(1)模式的结构

装饰模式主要包含四个角色。

  • 抽象构件(Component): 可以是一个接口或者抽象类,充当被装饰类的原始对象,规定了被装饰类的行为。
  • 具体构件(ConcreteComponent): 实现/继承 Component的一个具体对象,即被装饰对象。通过装饰角色为其添加一些职责。
  • 抽象装饰器(Decorator): 实现/继承 Component。通用的 ConcreteComponent的装饰列,其内部必然有一个属性指向 Component,主要是可以通过其子类扩展具体组件的功能。
  • 具体装饰器(ConcreteDecorator): Decorator的具体实现类,并给具体构件对象添加附加的责任,一般为其特有的功能。

装饰器模式j角色分配符合设计模式的里氏替换原则、依赖倒置原则,从而使得其具备很强的扩展性,最终满足开闭原则。

(2)结构图如下:(图来自网络)
在这里插入图片描述

3、优缺点

主要优点:

  • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
  • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
  • 装饰器模式完全遵守开闭原则

主要缺点:

  • 会出现更多的代码、更多的类,增加程序的复杂性。
4、使用场景
  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。
  • 当对象的功能要求可以动态地添加,也可以再动态地被撤销时。
  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。

在框架源码中使用也很广泛,比如:

  • JDK中的处理流 IO中包装流类等
  • Spring 中处理事务缓存的 TransactionAwareCacheDecorator类
  • Mybatis 中处理缓存设计的 Cache类等

二、模式的通用实现

代码如下:

public class DecoratorPattern {
    public static void main(String[] args) {
        Component p = new ConcreteComponent();
        p.operation();
        System.out.println("---------------装饰之后------------------");
        Component d = new ConcreteDecorator(p);
        d.operation();
    }
}

//抽象构件
interface Component {
    public void operation();
}

//具体构件
class ConcreteComponent implements Component {
    public ConcreteComponent() {
        System.out.println("创建具体构件角色");
    }

    // 相应的功能处理
    @Override
    public void operation() {
        System.out.println("调用具体构件角色的方法operation()");
    }
}

//抽象装饰器
class Decorator implements Component {
    // 持有的组件对象
    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        // 处理前后可以加一些附加功能
        component.operation();
    }
}

//具体装饰器
class ConcreteDecorator extends Decorator {
    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        // 在处理父类的方法时,可以在处理前后可以加一些附加功能
        // 如果不调用父类的方法,表示完全改写方法,实现新功能
        super.operation();
        addedFunction();
    }

    public void addedFunction() {
        System.out.println("为具体构件角色增加额外的功能addedFunction()");
    }
}

三、模式的应用实例

用一个卖煎饼果子的例子来说明。

  • 原味版:煎饼果子,总价格:5
  • 豪华版:辅料可自由搭配

1、抽象构件(Component)

public abstract class Battercake {

    protected abstract  String  getMessage();

    protected abstract int getPrice();
}

2、具体构件(ConcreteComponent)

public class BaseBattercake extends Battercake{

    @Override
    protected String getMessage() {
        return "煎饼果子";
    }

    @Override
    protected int getPrice() {
        return 5;
    }
}

3、抽象装饰器(Decorator)

public abstract class BattercakeDecorator extends Battercake{
    // 静态代理,委托
    private Battercake battercake;

    public BattercakeDecorator(Battercake battercake) {
        this.battercake = battercake;
    }

    @Override
    protected String getMessage() {
        return this.battercake.getMessage();
    }

    @Override
    protected int getPrice() {
        return this.battercake.getPrice();
    }

    // 可以加额外功能方法
    protected abstract void addedFunction();
}

4、具体装饰器(ConcreteDecorator)
这里给定三种辅料可供选择

  • 鸡蛋
public class EggDecorator extends BattercakeDecorator {

    public EggDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMessage() {
        return super.getMessage() + " + 1个鸡蛋";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 2;
    }

    @Override
    protected void addedFunction() {

    }

    // 可以加其特有的功能方法
}
  • 香肠
public class SausageDecorator extends BattercakeDecorator{

    public SausageDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMessage() {
        return super.getMessage() + " + 一个香肠";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 4;
    }

    @Override
    protected void addedFunction() {

    }
    // 可以加其特有的功能方法
}
  • 另类
public class OtherDecorator extends BattercakeDecorator{
    public OtherDecorator(Battercake battercake) {
        super(battercake);
    }

    @Override
    protected String getMessage() {
        return message();
    }

    @Override
    protected int getPrice() {
        return price();
    }

    @Override
    protected void addedFunction() {

    }

    // 可以加其特有的功能方法
    private String message(){
        return "老板,啥也不要,来根大葱";
    }
    private int price(){
        return 5;
    }
}

5、测试

public class Test {
    public static void main(String[] args) {
        System.out.println("===来一个基础版煎饼果子===");
        Battercake battercake = new BaseBattercake();
        System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");

        System.out.println("===来一个套餐A煎饼果子===");
        battercake = new EggDecorator(battercake);
        System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");

        System.out.println("===来一个套餐A+B煎饼果子===");
        battercake = new SausageDecorator(battercake);
        System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");


        System.out.println("===屌丝买煎饼果子===");
        Battercake battercake2 = new BaseBattercake();
        battercake2 = new OtherDecorator(battercake2);
        System.out.println(battercake2.getMessage() + ",总价格:" + battercake2.getPrice() + "元。");
    }
}

在这里插入图片描述

四、装饰模式的扩展

装饰模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,有时候抽象装饰器是可有可无的,如以下两种情况。(图来自网络)

1、只有一个具体装饰器,这样就不需要抽象装饰器,其结构图如下:
在这里插入图片描述
2、只有一个具体构件,这样就不需要抽象构件,抽象装饰者可以直接继承具体构件,其结构图如下:
在这里插入图片描述
3、只有一个具体构件和一个具体装饰者,这样抽象角色都不需要了,具体装饰者直接继承集体构件就可以了
在这里插入图片描述

参考文章:

—— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值