【设计模式】装饰者模式 ( 概念 | 适用场景 | 优缺点 | 与继承对比 | 定义流程 | 运行机制 | 案例分析 )

简介: 【设计模式】装饰者模式 ( 概念 | 适用场景 | 优缺点 | 与继承对比 | 定义流程 | 运行机制 | 案例分析 )

文章目录

I . 装饰者模式概念

II . 装饰者模式适用场景

III . 装饰者模式优缺点

IV . 装饰者模式与继承对比

V . 装饰者模式相关设计模式

VI . 装饰者模式四个相关类

VII . 装饰者模式实体装饰者类运行机制

VIII . 装饰者模式定义使用流程 ( 重点 )

IX . 装饰者模式 案例



I . 装饰者模式概念


装饰者模式概念 :



① 设计模式类型 : 结构性 ;


② 概念 : 不改变原有类的对象 , 动态地将额外的功能附加到该对象上 ;


③ 扩展对象功能 : 这种功能扩展方式比类继承更加灵活 ;


④ 装饰者模式 : 移除类中的被装饰功能 , 将被装饰类简化 , 区分类的核心职责 和 装饰功能 ;




II . 装饰者模式适用场景


装饰者模式适用场景 :



① 功能扩展 : 为一个类扩展功能 , 为其添加额外的职责 ; ( 强调扩展 )


② 动态添加撤销功能 : 为一个对象动态添加额外功能 , 同时这些被添加的功能还能被动态撤销 ; ( 强调动态 )




III . 装饰者模式优缺点


装饰者模式优点 :



① 扩展灵活 : 使用装饰者模式 , 比继承更加灵活 ; 使用装饰者模式扩展类功能 , 不会改变原来的类 ;


② 排列组合 : 对装饰类进行各种排列组合 , 可实现不同的扩展功能 ;


③ 开闭原则 : 装饰者模式符合开闭原则 , 被装饰的类 , 和装饰类相互独立 , 互不干扰 ;



装饰者模式缺点 :



① 程序复杂 : 需要编写更多的代码 , 生成更多的类 , 程序的复杂性增加了 ;


② 动态 / 多层 装饰 : 动态 / 多层 装饰一个类时 , 程序更复杂 ;




IV . 装饰者模式与继承对比


继承与装饰者模式对比 :



① 继承复杂 : 使用继承扩展功能 , 需要生成很多子类 , 系统复杂性增加 ;


② 继承静态 : 继承在编译时就要确定扩展的功能 , 是静态的 ;


③ 装饰者模式动态扩展 : 装饰者模式可以动态扩展功能 , 可以在代码运行时扩展功能 ;




V . 装饰者模式相关设计模式


1 . 装饰者模式与代理模式 :



① 注重点 : 装饰者模式注重动态扩展功能 ; 代理模式注重对对象访问的控制 , 代理类对用户隐藏具体细节 ;


② 实例对象的使用 : 装饰者模式将原始对象作为参数传递给装饰者类构造器 ; 代理模式中在代理类中创建实例对象 ;



2 . 装饰者模式与适配器模式 : 二者都是包装模式 ;



① 装饰者模式 : 装饰者模式中 , 装饰者和被装饰这实现相同的接口 , 或装饰者是被装饰者的子类 ;


② 适配器模式 : 适配器模式中 , 适配器和被适配的类有不同的接口 , 可能有部分接口重合 ;




VI . 装饰者模式四个相关类


装饰者模式四个相关类 :



① 抽象的 被装饰者类 : 这是核心 , 后面的三个类都需要继承该类 ;


② 实体的被装饰者类 : 定义装饰者模式时 , 用不到 , 在客户端被用户调用时 , 才初始化 ;


③ 抽象的装饰者类 : 所有装饰者类的父类 , 需要继承抽象的被装饰者类 ; ( 该类可选配 , 不是必须 )


④ 实体的装饰者类 : 继承 抽象的装饰者类 , 在该类中维护一个 抽象装饰者类对象 , 通过构造函数传入实体的被装饰者类 , 其实现的 抽象的装饰者类 方法中 , 需要调用传入的实体对象的对应方法 , 然后加入额外的操作 ;




VII . 装饰者模式实体装饰者类运行机制


实体的装饰者类运行机制 :



① 核心 : 核心是 抽象的 被装饰者类 类型 ,


② 装饰者类型 : 实体的装饰者类是 抽象的 被装饰者类 类型的 ,


③ 装饰者中维护的变量类型 : 其中维护的实例成员变量也是 抽象的 被装饰者类 类型的 ,


④ 装饰者模式运行 : 装饰者模式使用时 , 先创建一个 抽象的 被装饰者类 实例对象 , 创建一个装饰者对象 , 通过构造函数将上面的实例对象传入 , 整个装饰者模式就是为该实例对象进行扩展的 ;


⑤ 装饰可循环嵌套 : 实体的被装饰类类型是 抽象的 被装饰者类 类型的 , 其被装饰后 , 还是 抽象的 被装饰者类 类型的 , 然后还可以再次装饰 , 实体的被装饰类的动态功能的扩展 , 可以被无限装饰扩展 ;




VIII . 装饰者模式定义使用流程 ( 重点 )


1 . 定义抽象被装饰者 : 定义 抽象的 被装饰者类 , 将其要扩展的方法定义成抽象方法 ;



2 . 定义 ( 抽象的 ) 装饰者类 :



① 继承 抽象的 被装饰者类 : 装饰者类 继承 抽象的 被装饰者类 ;


② 维护 抽象的 被装饰者类 成员 : 在该类中维护一个 抽象的 被装饰者类 对象 , 该对象通过构造函数传入 ;


③ 实现抽象方法委托 : 装饰者类中的抽象方法 , 需要委托给类中维护的 抽象的 被装饰者类 对象 , 在实现的该抽象方法中 , 调用上面对象的对应方法 , 然后加上要扩展的代码 , 这些扩展的代码 , 就是装饰者模式位该对象动态扩展的功能 ;



3 . 定义实体对象 : 该对象是 抽象的 被装饰者类 类型的 , 是具体的实体功能 , 要实现实际的大块代码逻辑 , 所有的操作 , 装饰 , 都基于该实体对象类 ;


上面的装饰者类 只关心被装饰的方法 , 不定义其它内容 ;



4 . 使用装饰者模式 :



① 创建 抽象的 被装饰者类 实体对象 ;


② 装饰实体对象类 : 创建 抽象的 被装饰者类 类型的装饰者类 , 在构造函数中 , 传入 ① 中创建的 抽象的 被装饰者类 类型的 实体对象 ;


③ 再次装饰实体对象类 : 再次创建 抽象的 被装饰者类 类型的装饰者类 , 在构造函数中 , 传入 ② 中创建的 抽象的 被装饰者类 类型的 装饰者实体对象 , 这样就实现了二次装饰 ;



使用的对象类型是 抽象的 被装饰者类 , 被装饰的对象 , 传入装饰者类 , 相当于包装了一层 , 其对象类型还是 抽象的 被装饰者类 , 这个包装装饰可以循环嵌套 ;




IX . 装饰者模式 案例


1 . 案例需求 :



① 实体类对象 : 刚入学的学生 , 默认学习大学公共课 ,


② 装饰类对象 : 如果是计算机专业的学生 , 还要继续学习计算机专业课程 ,


③ 装饰类对象 : 如果是音乐专业的学生 , 需要继续学习音乐专业课程 ,


④ 二次装饰类对象 : 如果是先学习计算机 , 然后专修音乐 , 那么需要先学习计算机专业课程 , 然后学习音乐专业课程 ;



2 . 抽象的 被装饰者类 : 抽象的学生类 , 后面的计算机专业学生装饰者 , 音乐专业学生装饰者都继承该类 ;


package kim.hsl.design.decorator;
/**
 * 装饰者
 * 抽象的装饰者
 * 该类也继承 被装饰者 的抽象类
 */
public abstract class AbstractDecorator extends AbstractStudent {
    //声明抽象的被装饰者, 通过构造器将其类型 ( 或子类类型 ) 对象传入 , 注入实体类
    private AbstractStudent abstractStudent;
    public AbstractDecorator(AbstractStudent abstractStudent) {
        this.abstractStudent = abstractStudent;
    }
    /*
       调用实现的两个 抽象装饰者 方法
       实际上委托给了注入的 抽象装饰者 类型的对象执行的
       抽象装饰者 类型的对象是其子类对象
     */
    @Override
    protected String studyCourses() {
        return this.abstractStudent.studyCourses();
    }
}



3 . 刚入学的学生类 : 这是最普通的实体 , 是被装饰的实体类 , 一切装饰都是围绕着该实体来的 ;


package kim.hsl.design.decorator;
/**
 * 被装饰对象
 * 确定的实体类
 */
public class Student extends AbstractStudent {
    @Override
    protected String studyCourses() {
        return "学习大学公共课";
    }
}



4 . 抽象的被装饰者类 : 该类也是 抽象的被装饰者 类 AbstractStudent 的子类 , 该类中维护了 AbstractStudent 类型的成员变量 , 通过构造函数初始化 ; 其 studyCourses 方法需要委托给 abstractStudent 成员变量的 abstractStudent 方法 ;


package kim.hsl.design.decorator;
/**
 * 装饰者
 * 抽象的装饰者
 * 该类也继承 被装饰者 的抽象类
 */
public abstract class AbstractDecorator extends AbstractStudent {
    //声明抽象的被装饰者, 通过构造器将其类型 ( 或子类类型 ) 对象传入 , 注入实体类
    private AbstractStudent abstractStudent;
    public AbstractDecorator(AbstractStudent abstractStudent) {
        this.abstractStudent = abstractStudent;
    }
    /*
       调用实现的两个 抽象装饰者 方法
       实际上委托给了注入的 抽象装饰者 类型的对象执行的
       抽象装饰者 类型的对象是其子类对象
     */
    @Override
    protected String studyCourses() {
        return this.abstractStudent.studyCourses();
    }
}



5 . 计算机专业学生装饰者类 : 传入 AbstractStudent 成员变量 , studyCourses 方法中 , 在学习公共课基础上 ( 委托成员变量 ) , 还学习 计算机专业课程 ;


package kim.hsl.design.decorator;
/**
 * 实体装饰者类
 * 必须实现其带参数的构造器
 */
public class ComputerStudentDecorator extends AbstractDecorator {
    public ComputerStudentDecorator(AbstractStudent abstractStudent) {
        super(abstractStudent);
    }
    @Override
    protected String studyCourses() {
        return super.studyCourses() + " , 学习计算机专业课程";
    }
}


6 . 音乐专业学生装饰者类 :


package kim.hsl.design.decorator;
public class MusicStudentDecorator extends AbstractDecorator {
    public MusicStudentDecorator(AbstractStudent abstractStudent) {
        super(abstractStudent);
    }
    @Override
    protected String studyCourses() {
        return super.studyCourses() + " , 学习音乐专业课程";
    }
}



7 . 测试装饰者模式 : 其中测试了没有装饰的实体类 , 将其装饰成计算机专业学生 , 将其装饰成音乐专业学生 , 将其装饰成计算机转音乐专业的学生 ;


package kim.hsl.design.decorator;
public class Main {
    public static void main(String[] args) {
        //刚入学的学生
     Student student = new Student();
     System.out.println(student.studyCourses());
     //大二学习计算机专业课程
        AbstractStudent computerStudent = new ComputerStudentDecorator(student);
        System.out.println(computerStudent.studyCourses());
        //大二学习音乐专业课程
        AbstractStudent musicStudent = new MusicStudentDecorator(student);
        System.out.println(musicStudent.studyCourses());
        //先学计算机 , 专修音乐的学生
        AbstractStudent computerMusicStudent = new ComputerStudentDecorator(computerStudent);
        System.out.println(computerMusicStudent.studyCourses());
    }
}


目录
相关文章
|
6月前
|
设计模式 消息中间件 安全
【JUC】(3)常见的设计模式概念分析与多把锁使用场景!!理解线程状态转换条件!带你深入JUC!!文章全程笔记干货!!
JUC专栏第三篇,带你继续深入JUC! 本篇文章涵盖内容:保护性暂停、生产者与消费者、Park&unPark、线程转换条件、多把锁情况分析、可重入锁、顺序控制 笔记共享!!文章全程干货!
413 1
|
设计模式 存储 缓存
「全网最细 + 实战源码案例」设计模式——享元模式
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在减少大量相似对象的内存消耗。通过分离对象的内部状态(可共享、不变)和外部状态(依赖环境、变化),它有效减少了内存使用。适用于存在大量相似对象且需节省内存的场景。模式优点包括节省内存和提高性能,但会增加系统复杂性。实现时需将对象成员变量拆分为内在和外在状态,并通过工厂类管理享元对象。
472 92
|
11月前
|
设计模式 缓存 安全
【设计模式】【结构型模式】装饰者模式(Decorator)
一、入门 什么是装饰者模式? 装饰者模式(Decorator Pattern)是 Java 中常用的结构型设计模式,它能在不修改原有对象结构的前提下,动态地为对象添加额外的职责。 为什么要装饰者模式?
289 8
|
设计模式 存储 算法
「全网最细 + 实战源码案例」设计模式——命令模式
命令模式(Command Pattern)是一种行为型设计模式,将请求封装成独立对象,从而解耦请求方与接收方。其核心结构包括:Command(命令接口)、ConcreteCommand(具体命令)、Receiver(接收者)和Invoker(调用者)。通过这种方式,命令的执行、撤销、排队等操作更易扩展和灵活。 适用场景: 1. 参数化对象以操作。 2. 操作放入队列或远程执行。 3. 实现回滚功能。 4. 解耦调用者与接收者。 优点: - 遵循单一职责和开闭原则。 - 支持命令组合和延迟执行。 - 可实现撤销、恢复功能。 缺点: - 增加复杂性和类数量。
458 14
「全网最细 + 实战源码案例」设计模式——命令模式
|
设计模式 存储 Java
「全网最细 + 实战源码案例」设计模式——责任链模式
责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,允许将请求沿着处理者链进行发送。每个处理者可以处理请求或将其传递给下一个处理者,从而实现解耦和灵活性。其结构包括抽象处理者(Handler)、具体处理者(ConcreteHandler)和客户端(Client)。适用于不同方式处理不同种类请求、按顺序执行多个处理者、以及运行时改变处理者及其顺序的场景。典型应用包括日志处理、Java Web过滤器、权限认证等。
313 13
「全网最细 + 实战源码案例」设计模式——责任链模式
|
设计模式 算法 开发者
「全网最细 + 实战源码案例」设计模式——策略模式
策略模式(Strategy Pattern)是一种行为型设计模式,用于定义一系列可替换的算法或行为,并将它们封装成独立的类。通过上下文持有策略对象,在运行时动态切换算法,提高代码的可维护性和扩展性。适用于需要动态切换算法、避免条件语句、经常扩展算法或保持算法独立性的场景。优点包括符合开闭原则、运行时切换算法、解耦上下文与策略实现、减少条件判断;缺点是增加类数量和策略切换成本。示例中通过定义抽象策略接口和具体策略类,结合上下文类实现动态算法选择。
506 8
「全网最细 + 实战源码案例」设计模式——策略模式
|
设计模式 SQL 算法
「全网最细 + 实战源码案例」设计模式——模板方法模式
模板方法模式是一种行为型设计模式,定义了算法的骨架并在父类中实现不变部分,将可变部分延迟到子类实现。通过这种方式,它避免了代码重复,提高了复用性和扩展性。具体步骤由抽象类定义,子类实现特定逻辑。适用于框架设计、工作流和相似算法结构的场景。优点包括代码复用和符合开闭原则,缺点是可能违反里氏替换原则且灵活性较低。
383 7
「全网最细 + 实战源码案例」设计模式——模板方法模式
|
设计模式 Java 数据安全/隐私保护
Java 设计模式:装饰者模式(Decorator Pattern)
装饰者模式属于结构型设计模式,允许通过动态包装对象的方式为对象添加新功能,提供比继承更灵活的扩展方式。该模式通过组合替代继承,遵循开闭原则(对扩展开放,对修改关闭)。
|
设计模式 存储 安全
「全网最细 + 实战源码案例」设计模式——组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示“部分-整体”的层次结构。它允许客户端以一致的方式对待单个对象和对象集合,简化了复杂结构的处理。组合模式包含三个主要组件:抽象组件(Component)、叶子节点(Leaf)和组合节点(Composite)。通过这种模式,客户端可以统一处理简单元素和复杂元素,而无需关心其内部结构。适用于需要实现树状对象结构或希望以相同方式处理简单和复杂元素的场景。优点包括支持树形结构、透明性和遵循开闭原则;缺点是可能引入不必要的复杂性和过度抽象。
449 22
|
设计模式 前端开发 数据库
「全网最细 + 实战源码案例」设计模式——桥接模式
桥接模式(Bridge Pattern)是一种结构型设计模式,通过将抽象部分与实现部分分离,使它们可以独立变化,从而降低代码耦合度,避免类爆炸,提高可扩展性。其结构包括实现类接口、具体实现类、抽象类和精确抽象类。适用于多维度扩展类、隐藏实现细节、简化庞杂类以及运行时切换实现方法的场景。优点包括高扩展性、隐藏实现细节、遵循开闭原则和单一职责原则;缺点是可能增加代码复杂度。示例中展示了不同操作系统播放不同格式视频文件的实现。
391 19