# 装饰器模式(Decorator Pattern)

目录: https://note.dolyw.com/design/ (opens new window)

代码地址

# 1. 介绍

装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装,这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能

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

# 1.1. 特点

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

# 1.2. 结构

  • 抽象构件(Component):定义一个抽象接口以规范准备接收附加责任的对象
  • 具体构件(ConcreteComponent):实现抽象构件,通过装饰角色为其添加一些职责
  • 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
  • 具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任

# 1.3. 优缺点

  • 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活
  • 主要解决:我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀
  • 何时使用:在不想增加很多子类的情况下扩展类
  • 如何解决:将具体功能职责划分,同时继承装饰者模式
  • 关键代码: Component 类充当抽象角色,不应该具体实现。修饰类引用和继承 Component 类,具体扩展类重写父类方法
  • 优点
    • 装饰类和被装饰类可以独立发展,不会相互耦合
    • 是继承的一个替代模式
    • 可以动态扩展一个实现类的功能
  • 缺点
    • 多层装饰比较复杂,会增加许多子类,过度使用会增加程序得复杂性

# 1.4. 举例

  • 在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式
  • 比如吃面,有汤面,炒面,面可以加配菜装饰,煎蛋,卤蛋,牛肉等,但是不管怎么加配菜,都还是一份面

# 2. 代码

用吃面的例子,模式结构:抽象构件、具体构件、抽象装饰、具体装饰

# 2.1. 抽象构件

/**
 * 面条抽象构件
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:30
 */
public interface NoodleComponent {

    /**
     * 备注
     *
     * @param
     * @return java.lang.String
     * @throws
     * @author wliduo[i@dolyw.com]
     * @date 2022/1/18 16:31
     */
    String remark();

    /**
     * 价格
     *
     * @param
     * @return java.lang.Integer
     * @throws
     * @author wliduo[i@dolyw.com]
     * @date 2022/1/18 16:31
     */
    Integer price();

}

# 2.2. 具体构件

/**
 * 炒面具体构件
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:30
 */
public class FryNoodleConcreteComponent implements NoodleComponent {

    @Override
    public String remark() {
        return "炒面10快";
    }

    @Override
    public Integer price() {
        return 10;
    }
}
/**
 * 汤面具体构件
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:30
 */
public class SoupNoodleConcreteComponent implements NoodleComponent {

    @Override
    public String remark() {
        return "汤面8快";
    }

    @Override
    public Integer price() {
        return 8;
    }
}

# 2.3. 抽象装饰

/**
 * 配菜抽象装饰
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:40
 */
public abstract class AbstractSideDishDecorator implements NoodleComponent {

    private NoodleComponent noodleComponent;

    public AbstractSideDishDecorator(NoodleComponent noodleComponent) {
        this.noodleComponent = noodleComponent;
    }

    @Override
    public String remark() {
        return noodleComponent.remark();
    }

    @Override
    public Integer price() {
        return noodleComponent.price();
    }
}

# 2.4. 具体装饰

/**
 * 牛肉具体装饰
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:44
 */
public class BeefConcreteDecorator extends AbstractSideDishDecorator {

    public BeefConcreteDecorator(NoodleComponent noodleComponent) {
        super(noodleComponent);
    }

    @Override
    public String remark() {
        return super.remark() + " 加份牛肉5快";
    }

    @Override
    public Integer price() {
        return super.price() + 5;
    }
}
/**
 * 煎蛋具体装饰
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:44
 */
public class FriedEggConcreteDecorator extends AbstractSideDishDecorator {

    public FriedEggConcreteDecorator(NoodleComponent noodleComponent) {
        super(noodleComponent);
    }

    @Override
    public String remark() {
        return super.remark() + " 加份煎蛋3快";
    }

    @Override
    public Integer price() {
        return super.price() + 3;
    }
}
/**
 * 卤蛋具体装饰
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:44
 */
public class MarinatedEggConcreteDecorator extends AbstractSideDishDecorator {

    public MarinatedEggConcreteDecorator(NoodleComponent noodleComponent) {
        super(noodleComponent);
    }

    @Override
    public String remark() {
        return super.remark() + " 加份卤蛋2快";
    }

    @Override
    public Integer price() {
        return super.price() + 2;
    }
}

# 2.5. 执行

/**
 * 装饰器模式
 * 通过不同的装饰器自由组合
 * 我们可以灵活的组装出各式各样的面加配菜
 * 这正是装饰者模式的优点
 * 但明显可以看出代码变复杂了
 *
 * @author wliduo[i@dolyw.com]
 * @date 2022/1/18 16:05
 */
public class Main {

    public static void main(String[] args) {
        // 汤面
        NoodleComponent soupNoodleConcreteComponent = new SoupNoodleConcreteComponent();
        // 加牛肉
        soupNoodleConcreteComponent = new BeefConcreteDecorator(soupNoodleConcreteComponent);
        // 加煎蛋
        soupNoodleConcreteComponent = new FriedEggConcreteDecorator(soupNoodleConcreteComponent);
        System.out.println(soupNoodleConcreteComponent.remark());
        System.out.println(soupNoodleConcreteComponent.price());
        System.out.println("----------------------");
        // 炒面
        NoodleComponent fryNoodleConcreteComponent = new FryNoodleConcreteComponent();
        // 加牛肉
        fryNoodleConcreteComponent = new BeefConcreteDecorator(fryNoodleConcreteComponent);
        // 加卤蛋
        fryNoodleConcreteComponent = new MarinatedEggConcreteDecorator(fryNoodleConcreteComponent);
        System.out.println(fryNoodleConcreteComponent.remark());
        System.out.println(fryNoodleConcreteComponent.price());
        System.out.println("-----------------------");
        // 炒面
        NoodleComponent fryNoodleConcreteComponentEasy = new FryNoodleConcreteComponent();
        // 加牛肉加卤蛋加煎蛋
        fryNoodleConcreteComponentEasy =
                new BeefConcreteDecorator(
                        new MarinatedEggConcreteDecorator(new FriedEggConcreteDecorator(fryNoodleConcreteComponentEasy)));
        System.out.println(fryNoodleConcreteComponentEasy.remark());
        System.out.println(fryNoodleConcreteComponentEasy.price());
    }

}

输出

汤面8快 加份牛肉5快 加份煎蛋316
----------------------
炒面10快 加份牛肉5快 加份卤蛋217
-----------------------
炒面10快 加份煎蛋3快 加份卤蛋2快 加份牛肉520
上次更新时间: 2023-12-15 03:14:55