设计模式-装饰模式

文章目录

  • 一、简介
  • 二、基本概念
  • 三、装饰模式的结构和实现
    • 类图解析:
    • 装饰器的实现方式
      • 继承实现:
      • 组合实现:
      • 继承和组合对比
  • 四、装饰模式的应用场景
  • 五、与其他模式的关系
  • 六、总结

一、简介

装饰模式是一种结构型设计模式,它允许动态地向对象添加额外的功能。

二、基本概念

在这里插入图片描述

  1. 装饰模式定义:在不改变原有对象结构的情况下,通过对其进行包装拓展,以达到增强功能的目的。
  2. 装饰器角色:负责给组件对象附加额外的功能,实现了与组件具有相同接口的装饰器类。
  3. 组件角色:拥有核心功能的原始对象。
  4. 抽象组件角色:定义了组件对象的接口,可以是抽象类或接口。
  5. 具体组件角色:实现了抽象组件角色的具体对象。

三、装饰模式的结构和实现

类图解析:

// 抽象组件角色
public interface Component {void operation();
}// 具体组件角色
public class ConcreteComponent implements Component {public void operation() {// 实现核心功能System.out.println("这是具体组件角色的核心功能");}
}// 装饰器角色
public abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}public void operation() {component.operation();}
}// 具体装饰器角色
public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}public void operation() {// 添加额外功能代码System.out.println("具体装饰器角色:"+"执行核心组件的功能前111");super.operation();// 添加额外功能代码System.out.println("具体装饰器角色:"+"执行核心组件的功能后2222");}
}
  1. 客户端代码示例:
Component component = new ConcreteComponent(); // 创建具体组件对象
component.operation(); // 调用核心功能Component decoratedComponent = new ConcreteDecorator(component); // 使用具体装饰器装饰组件
decoratedComponent.operation(); // 调用增强功能

在这里插入图片描述

装饰器的实现方式

继承实现:

具体装饰器继承装饰器抽象类,通过重写父类方法实现功能拓展
  1. 继承实现方式:
// 抽象组件角色
interface Component {void operation();
}// 具体组件角色
class ConcreteComponent implements Component {public void operation() {// 执行核心功能System.out.println("执行核心功能");}
}// 抽象装饰器角色
abstract class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}public void operation() {component.operation();}
}// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}public void operation() {super.operation();// 添加额外的功能代码System.out.println("添加额外的功能代码A");}
}class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}public void operation() {super.operation();// 添加额外的功能代码System.out.println("添加额外的功能代码B");}
}// 使用示例
public class Main {public static void main(String[] args) {// 创建具体组件对象Component component = new ConcreteComponent();// 创建具体装饰器对象,并包装组件对象Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);// 调用装饰器的操作方法,实现功能的拓展decoratorB.operation();}
}

组合实现:

具体装饰器持有装饰器抽象类的实例,通过调用实例方法实现功能拓展。
2. 组合实现方式:

// 抽象组件角色
interface Component {void operation();
}// 具体组件角色
class ConcreteComponent implements Component {public void operation() {// 执行核心功能System.out.println("执行核心功能");}
}// 装饰器角色
class Decorator implements Component {protected Component component;public Decorator(Component component) {this.component = component;}public void operation() {component.operation();}
}// 具体装饰器角色
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}public void operation() {super.operation();// 添加额外的功能代码System.out.println("添加额外的功能代码A");}
}class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}public void operation() {super.operation();// 添加额外的功能代码System.out.println("添加额外的功能代码B");}
}// 使用示例
public class Main {public static void main(String[] args) {// 创建具体组件对象Component component = new ConcreteComponent();// 创建具体装饰器对象,并包装组件对象Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);// 调用装饰器的操作方法,实现功能的拓展decoratorB.operation();}
}

这两个示例中,都有一个抽象的组件角色(Component),一个具体的组件角色(ConcreteComponent),以及几个具体的装饰器角色(ConcreteDecorator)。具体装饰器角色在构造函数中接收一个组件对象,并在自身的 operation() 方法中调用组件对象的 operation() 方法,并添加额外的功能代码。

在使用示例中,我们创建了具体组件对象和具体装饰器对象,并将它们进行组合,最后调用装饰器的 operation() 方法来实现功能的拓展。

继承和组合对比

在装饰器模式中,继承实现和组合实现是两种常见的方式。它们在实现装饰器功能时略有不同:
继承实现:

  • 优点:
    • 简单直接:通过继承抽象装饰器类,具体装饰器可以直接重写方法并添加额外功能。
    • 可复用性高:可以轻松地创建多个具体装饰器,并进行组合拓展。
  • 缺点:
    • 类爆炸:每个具体装饰器都需要创建一个新的类,当装饰器数量增多时,类的数量也会大量增加。
    • 静态结构:类的组合和功能拓展是在编译时静态决定的,无法动态地改变组合方式。

组合实现:

  • 优点:
    • 灵活组合:具体装饰器持有抽象装饰器对象,可以在运行时动态地组合不同的装饰器对象,实现不同的功能拓展组合。
    • 类结构简单:相对于继承实现,不需要创建过多的具体装饰器类,类结构相对简单。
  • 缺点:
    • 代码复杂度较高:需要在具体装饰器中额外处理抽象装饰器对象的方法调用。可能需要在抽象装饰器中定义一些默认实现,以避免空指针异常。

根据具体需求和设计考虑,可以选择适合的实现方式。继承实现适用于静态且数量有限的装饰器组合,而组合实现适用于动态和灵活的装饰器组合。两种实现方式都能实现装饰器模式的基本功能,只是在代码结构和使用方式上略有差异。

四、装饰模式的应用场景

  1. 动态添加功能:当需要在不修改现有代码的情况下,动态地给对象添加新功能时,装饰模式可以很好地满足这一需求。
  2. 避免子类爆炸:利用装饰模式,可以避免通过创建大量子类来实现各种功能组合的问题。
  3. 透明性 vs. 安全性:装饰模式中的装饰器和组件具有相同的接口,使得对于客户端而言,无需关心具体是使用了原始组件还是装饰器对象,实现了透明性。

五、与其他模式的关系

  1. 装饰模式 vs. 适配器模式:装饰模式侧重于给对象动态添加功能,而适配器模式则是为了让不兼容的类能够协同工作。
  2. 装饰模式 vs. 组合模式:装饰模式和组合模式都采用了递归组合的思想,但装饰模式着重于给对象添加功能,而组合模式着重于构建对象的树形结构。
  3. 装饰模式 vs. 桥接模式:桥接模式将抽象部分和实现部分解耦,而装饰模式则是在不改变对象结构的基础上,拓展其功能。

六、总结

装饰模式通过包装对象实现功能的动态拓展,使得系统具有更高的灵活性和可扩展性。它应用广泛,在动态添加功能、避免子类爆炸等场景都很有价值。同时,要注意使用装饰模式时,保持透明性和安全性的平衡,确保装饰器和组件具有一致的接口。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/99541.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Unity-Cinemachine相机】相机跟随之Transposer属性

相机跟随和瞄准行为 Transposer:虚拟相机将在某个固定的偏移或距离上跟随目标移动 上面的偏移量就是Follow Offset Binding Mode决定Follow Offset是目标本地坐标系下的身后十米还是世界坐标系下的身后十米 Lock To Target On Assign:锁定自己和目标本地…

【Git-Exception】Git报错:fatal: unable to auto-detect email address

报错信息: *** Please tell me who you are. Run git config --global user.email “youexample.com” git config –global user.name “Your Name” to set your account’s default identity. Omit --global to set the identity only in this repository. fatal…

Unity汉化一个插件 制作插件汉化工具

我是编程一个菜鸟,英语又不好,有的插件非常牛!我想学一学,页面全是英文,完全不知所措,我该怎么办啊...尝试在Unity中汉化一个插件 效果: 思路: 如何在Unity中把一个自己喜欢的插件…

nmp ERR! code ERR SOCKET TIMEOUT nmp ERR!network npmSocket timeout(已解决)

当安装vue-cli时,出现超时错误 npm ERR! code ECONNRESET npm ERR! network This is a problem related to network connectivity npm ERR! code ECONNRESET npm ERR! network aborted npm ERR! network This is a problem related to network connectivity. npm E…

如何判断自己的qt版本呢?

如何判断自己的qt版本呢? 前情提要很简单,按照如下图所示,即可查看当前打开的qtCreator的版本如何打开5.15.2版本的qtCreator呢?安装教程 前情提要 我的电脑已经安装了qt5.14.1,然后我又安装了qt5.15.2,我想尝试一下同一台电脑能否适应两个版本的qt? 当我安装完成qt5.15.2后…

Mac Homebrew中常用的 Brew 命令

Mac 中常用的 Brew 命令集 Brew(Homebrew)是一个强大的包管理器,用于在 macOS 上安装、更新和管理各种软件包。它使得在 Mac 上安装开发工具、应用程序和库变得轻松和便捷。本博客将介绍一些在 Mac 中常用的 Brew 命令,以帮助您更…

Astro建站教程:安装nodejs,npm下载Astro,安装扩展

下载Nodejs LTS版:https://nodejs.org/en 安装步骤全默认即可,安装路径可以根据自己的爱好更改在桌面右键打开cmd或powershell,输入node -v和npm -v测试是否安装成功 浏览器打开https://docs.astro.build/en/install/auto/ 复制里面的npm cre…

MyBatisPlus入门篇2 - 条件查询、查询投影、查询条件、id生成策略、多记录操作、逻辑删除

目录 1.条件查询、多条件查询 MyBatisPlus将书写复杂的SQL查询条件进行了封装&#xff0c;使用编程的形式完成查询条件的组合。 Test void testGetByCondition() {// 方式一&#xff1a;按条件查询QueryWrapper<User> qw new QueryWrapper<User>();qw.lt("…

W5100S_EVB_PICO 做MQTT测试(十二)

前言 上一章我们用W5100S_EVB_PICO 开发板做Ping测试&#xff0c;那么本章我们进行W5100S_EVB_PICO MQTT的测试。 什么是mqtt&#xff1f; MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订…

Lua语法结构

Lua基础 注释 print("hello.") -- 单行注释的写法 --[[ 多行注释的写法 --]]标识符 关键字 **and **break**do **else**elseif ****end **falsefor**function **ifinlocalnilnotorrepeatreturnthentrueuntil**while ** 数据类型 nil** boolean**** number**** st…

计算机网络的故事——确保Web安全的Https

确保Web安全的Https 文章目录 确保Web安全的Https一、HTTP 的缺点二、HTTP 加密 认证 完整性保护 HTTPS 一、HTTP 的缺点 1、明文传输 通信加密&#xff0c;HTTP协议中没有加密机制&#xff0c;但是可以通过SSL(Secure Socket Layer&#xff0c;安全套接字层)或TLE(Transpor…

算法做题记录

一、递推 95.费解的开关 #include<iostream> #include<cstring> using namespace std;const int N 8;char a[N][N],s[N][N]; int T; int ans20,cnt; int dir[5][2]{1,0,-1,0,0,1,0,-1,0,0};void turn(int x,int y) {for(int i0;i<5;i){int xx xdir[i][0];in…