设计模式九:装饰器模式

1、装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

角色:

  • 抽象组件角色(Component): 定义可以动态添加任务的对象的接口

  • 具体组件角色(ConcreteComponent):定义一个要被装饰器装饰的对象,即 Component 的具体实现

  • 抽象装饰器(Decorator): 维护对象和其子类的引用

  • 具体装饰器角色(ConcreteDecorator):向对象添加新的功能或行为特征
    9.1装饰器模型

//抽象组件角色
public interface Compont {
    void operation();
}

//具体组件角色
public class ConcreteComponent implements Compont {
    @Override
    public void operation() {
        System.out.println("我是 具体构件类");
    }
}

//抽象装饰器
public interface Decorator {
    void operation();
}

//具体装饰器角色
public class ConcreteDecoratorA implements Decorator {
    private Compont compont;

    public ConcreteDecoratorA(Compont compont) {
        this.compont = compont;
    }

    @Override
    public void operation() {
        System.out.println("我是装饰者A,我先执行一些逻辑,接下来再执行构建类的方法");
        compont.operation();
    }
}

public class ConcreteDecoratorB implements Decorator {
    private Compont compont;

    public ConcreteDecoratorB(Compont compont) {
        this.compont = compont;
    }

    @Override
    public void operation() {
        System.out.println("我是装饰者B,我先执行一些逻辑,接下来再执行构建类的方法");
        compont.operation();
    }
}

2、示例

珍珠奶茶示例,购买珍珠奶茶时,往里面加不同的小料,价格不同

9.2珍珠奶茶示例

//奶茶接口
public interface MilkyTea {
    double cost();
}
//珍珠奶茶
public class PearlMilkyTea implements MilkyTea{
    @Override
    public double cost() {
        return 13.0;
    }
}
//修饰器接口
public abstract class MilkyTeaDecorator implements MilkyTea{
    private MilkyTea milkyTea;
    public MilkyTeaDecorator(MilkyTea milkyTea){
        this.milkyTea = milkyTea;
    }
    @Override
    public double cost() {
        return milkyTea.cost();
    }
}

/**
 * 椰果奶茶
 */
public class CoconutDecorator extends MilkyTeaDecorator{

    public CoconutDecorator(MilkyTea milkyTea) {
        super(milkyTea);
    }

    @Override
    public double cost() {
        System.out.println("添加椰果");
        return super.cost() + 2.0;
    }
}


/**
 * 布丁奶茶
 */
public class PuddingDecorator extends MilkyTeaDecorator{

    public PuddingDecorator(MilkyTea milkyTea) {
        super(milkyTea);
    }

    @Override
    public double cost() {
        System.out.println("添加布丁");
        return super.cost() + 1.5;
    }
}
//测试类
public class Client {
    public static void main(String[] args) {
        MilkyTea milkyTea = new PearlMilkyTea();
        milkyTea = new CoconutDecorator(milkyTea);
        milkyTea = new PuddingDecorator(milkyTea);
        System.out.println(milkyTea.cost());
    }
}

创建珍珠奶茶对象,放入不同的修饰类的构造方法中达到修饰器的效果

如果需要在 添加小料 之后还要扩展甜度,则需要

1、增加 甜度 抽象修饰类,构造方法中需要有 MilkyTeaDecorator ,并实现MilkyTea

2、增加不同的具体修饰类,继承甜度抽象类

3、在测试类中

MilkyTea milkyTea = new PearlMilkyTea();
milkyTea = new CoconutDecorator(milkyTea);
milkyTea = new SevenSugerDecorator(milkyTea);

由此可见,装饰器模式的优缺点“

优点

  1. 装饰类和被装饰类可以独立发展,不会相互耦合。
  2. 相比于继承,更加的轻便、灵活。
  3. 可以动态扩展一个实现类的功能,不必修改原本代码

缺点

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

3、装饰器模式与适配器模式

适配器模式和装饰器模式都可以在原类文件方法的基础上修改、增强,但侧重点不一样,
适配器模式重在将一个接口转换为另一个接口
装饰器模式侧重对原类文件方法的增强,但接口还是同一个接口

最直观的区别可以理解为

  • 适配器模式是为了新的接口能够复用老接口的方法,改变接口名称,不改变老接口方法的内容(当然可以增强)

  • 装饰器模式是直接增强对象的方法

4、装饰器模式和代理模式

相同点: 装饰类(代理类)与被装饰类(被代理类)都需要实现相同的接口;

不同点:

  • 1、强调的重点不同,装饰器类强调通过层层装饰来扩展附属功能,而代理模式强调对代理过程的控制;
  • 2、调用的方式不同,一般装饰器模式是通过构造器层层嵌套的形式,而代理模式隐藏被代理对象的内部细节;

5、java io流的装饰器模式

java中io的基础类中使用到了装饰器模式:

9.3javaIO

其中缓冲字节流和缓冲字符流就是普通流的装饰器,具体可以参考一下两篇文章

Java面试必知必会 —— 全面解读 Java IO(基础篇)

Java面试必知必会 —— 全面解读 Java IO (装饰器模式篇)

相关推荐

  1. 装饰设计模式

    2024-03-13 11:52:02       51 阅读
  2. 设计模式装饰模式

    2024-03-13 11:52:02       66 阅读
  3. 设计模式装饰模式

    2024-03-13 11:52:02       36 阅读
  4. 设计模式 —— 装饰模式

    2024-03-13 11:52:02       24 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-13 11:52:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-13 11:52:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-13 11:52:02       87 阅读
  4. Python语言-面向对象

    2024-03-13 11:52:02       96 阅读

热门阅读

  1. kafka入门教程

    2024-03-13 11:52:02       48 阅读
  2. 镜片行业调研报告

    2024-03-13 11:52:02       32 阅读
  3. 中间件MQ面试题之Kafka

    2024-03-13 11:52:02       50 阅读
  4. 每天几道面试题|Kafka基础概念(一)

    2024-03-13 11:52:02       46 阅读
  5. 【C++】内存泄漏

    2024-03-13 11:52:02       37 阅读
  6. 阿里云数据盘挂载目录

    2024-03-13 11:52:02       45 阅读
  7. C++内存对齐知识点总结

    2024-03-13 11:52:02       39 阅读