设计模式07-结构型模式(装饰模式/外观模式/代理模式/Java)
4.4 装饰模式
4.4.1 装饰模式的定义
1.动机:在不改变一个对象本身功能的基础上给对象增加额外的新行为
2.定义:动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活
4.4.2 装饰模式的结构与分析

//抽象构件类
public interface Component {public void operation();
}
//具体构建类
public class ConcreteComponent implements Component{@Overridepublic void operation() {}
}
//装饰者类
public class Decorator implements Component {private Component component;//要装饰哪个构件public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
//具体装饰者类
public class ConcreteDecorator extends Decorator{public ConcreteDecorator(Component component) {super(component);}public void preAddOperation() {}public void operation() {preAddOperation();super.operation();postAddOperation();}public void postAddOperation() {}
}
//客户端
public class Main {public static void main(String[] args) {//要装饰的构建ConcreteComponent component = new ConcreteComponent();//创建装饰类Decorator decorator = new Decorator(component);decorator.operation();}
}
-
装饰模式是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。
-
透明装饰模式和半透明装饰模式
**透明装饰模式:**客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。无法在客户端单独调用新增方法addedBehavior()
**半透明装饰模式:**用具体装饰类型来定义装饰之后的对象,而具体构件使用抽象构件类型来定义。最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象(此时已经不再是Component类型了)
4.4.3 装饰模式的案例
某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能。现使用装饰模式来设计该图形界面构件库。

//抽象构件类
public interface Component {public void display();
}
public class Window implements Component{@Overridepublic void display() {System.out.println("一个窗口");}
}
//抽象装饰类
public class Decorator implements Component{private Component component;public Decorator(Component component) {this.component = component;}@Overridepublic void display() {component.display();}
}
//装饰类
public class BorderDecoration extends Decorator{public BorderDecoration(Component component) {super(component);}public void display() {addBorder();super.display();}public void addBorder() {System.out.println("添加黑色边框");}
}
public class ScrollBarDecorator extends Decorator {public ScrollBarDecorator(Component component) {super(component);}public void display() {addScrollBar();super.display();}public void addScrollBar() {System.out.println("添加滚动条");}
}
//客户端
public class Main {public static void main(String[] args) {Window window = new Window();//添加滚动条ScrollBarDecorator decorator1 = new ScrollBarDecorator(window);//添加黑边框BorderDecoration decorator2 = new BorderDecoration(decorator1);decorator2.display();}
}
4.4.4 装饰模式的优缺点
| 优点 | 缺点 |
|---|---|
| 1.装饰模式可以动态的扩展一个对象的功能,且比继承简洁,不会导致类的个数急剧增多 | 1.装饰模式进行系统设计时,会产生很多小对象,占用资源 |
| 2.可以对一个对象多次装饰 | 2.比继承更容易犯错 |
| 3.构件类和装饰类可以独立变化,无需修改源代码符合开闭原则 |
4.4.5 装饰模式的适用场景
-
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责
-
当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式
4.5 外观模式
4.5.1 外观模式的定义
**1.模式动机:**一个客户类需要和多个业务类交互,有时候这些需要交互的业务类会作为一个整体出现,如何简化这种主系统和子系统之间的交互。
**2.模式定义:**为子系统中的一组接口提供一个统一的入口,外观模式定义了一个高层接口,这个接口使得子系统更加容易使用,外部与子系统的通信通过一个统一的外观对象进行。
4.5.2 外观模式的结构与分析

- 外观对象是迪米特法则的一种具体实现。
- 子系统符合单一职责原则。
- 但是当新加入一个子系统时,需要修改子系统角色,这不符合开闭原则。
- 一个系统可能有多个外观类
- 不要通过外观类给子系统增加行为
- 为了在增加外观类的时候符合开闭原则,可以增加一个抽象外观类
public class Facade {private SubSystem1 subSystem1 = new SubSystem1();private SubSystem2 subSystem2 = new SubSystem2();public void method() {subSystem1.method1();subSystem2.method2();}
}
public class SubSystem1 {public void method1() {}
}
public class SubSystem2 {public void method2() {}
}
4.5.3 外观模式的案例
现在考察一个电源总开关的例子,以便进一步说明外观模式。为了使用方便,一个电源总开关可以控制四盏灯、和一台电视机的启动和关闭。通过该电源总开关可以同时控制上述所有电器设备,使用外观模式设计该系统。
public class Light {private String location;public Light(String location) {this.location = location;}public void on() {System.out.println("打开" + location + "的灯");}public void off() {System.out.println("关闭" + location + "的灯");}
}
public class TV {public void on() {System.out.println("打开电视");}public void off() {System.out.println("关闭电视");}
}
public class Facade {private Light[] lightArray = new Light[4];private TV tv;public Facade() {lightArray[0] = new Light("客厅");lightArray[1] = new Light("厨房");lightArray[2] = new Light("卫生间");lightArray[3] = new Light("卧室");tv = new TV();}public void on() {lightArray[0].on();lightArray[1].on();lightArray[2].on();lightArray[3].on();tv.on();}public void off() {lightArray[0].off();lightArray[1].off();lightArray[2].off();lightArray[3].off();tv.off();}
}
public class Main {public static void main(String[] args) {Facade facade = new Facade();facade.on();facade.off();}
}
4.5.4 外观模式的优缺点
| 优点 | 缺点 |
|---|---|
| 1.对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易 | 1.不能很好地限制客户端直接使用子系统类 |
| 2.对客户端和子系统进行解耦 | 2.如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则 |
| 3.子系统的变化独立,不会影响到其他子系统和客户端 |
4.5.5 外观模式的适用场景
-
要为访问一系列复杂的子系统提供一个简单入口
-
客户端程序与多个子系统之间存在很大的依赖性
-
在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度
4.6 代理模式
4.6.1 代理模式的定义
**1.模式动机:**通过引入一个新的对象来实现对真实对象的操作,或者将新的对象作为真实对象的一个替身,引入代理对象来间接访问一个对象
2.模式定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用
4.6.2 代理模式的结构与分析
public interface Subject {public void request();
}
public class Real implements Subject{@Overridepublic void request() {}
}
public class Proxy implements Subject{private Real real = new Real();public void preRequest() {}@Overridepublic void request() {preRequest();real.request();postRequest();}public void postRequest() {}
}
4.6.3 代理模式的案例
- 保护代理:
在一个论坛中已注册用户和游客的权限不同,已注册的用户拥有发帖、修改自己的注册信息、修改自己的帖子等功能;而游客只能看到别人发的帖子,没有其他权限。使用代理模式来设计该权限管理模块。

public interface Permission {public void readBolg();public void writeBolg();public void updateBolg();public void updateUserInfo();
}public class RealPermission implements Permission{@Overridepublic void readBolg() {System.out.println("阅读博客");}@Overridepublic void writeBolg() {System.out.println("写博客");}@Overridepublic void updateBolg() {System.out.println("修改博客");}@Overridepublic void updateUserInfo() {System.out.println("修改用户信息");}
}public class ProxyPermission implements Permission{private int state;private RealPermission permission;public ProxyPermission(int state) {this.state = state;permission = new RealPermission();}@Overridepublic void readBolg() {permission.readBolg();}@Overridepublic void writeBolg() {if (state == 0) {System.out.println("游客模式不能写博客");} else {permission.writeBolg();}}@Overridepublic void updateBolg() {if (state == 0) {System.out.println("游客模式不能更改博客");} else {permission.updateBolg();}}@Overridepublic void updateUserInfo() {if (state == 0) {System.out.println("游客模式不能更改信息");} else {permission.updateUserInfo();}}
}
4.6.4 代理模式的优缺点
| 优点 | 缺点 |
|---|---|
| 1.能够协调调用者和被调用者,在一定程度上降低了系统的耦合度 | 1.增加了代理对象,有些类型的代理模式可能会造成请求的处理速度变慢 |
| 2.客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则 | 2.实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂 |
4.6.5 代理模式的适用场景
| 代理模式 | 描述 |
|---|---|
| 远程代理 | 当客户端对象需要访问远程主机中的对象时 |
| 虚拟代理 | 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时 |
| 缓冲代理 | 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时 |
| 保护代理 | 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时 |
| 智能引用代理 | 当需要为一个对象的访问(引用)提供一些额外的操作 |
| 防火墙代理 | 保护目标不让恶意用户接近。 |
| 同步化代理 | 使几个用户能够同时使用一个对象而没有冲突。 |
| Copy-on-Write代理 | 把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作。 |
相关文章:
设计模式07-结构型模式(装饰模式/外观模式/代理模式/Java)
4.4 装饰模式 4.4.1 装饰模式的定义 1.动机:在不改变一个对象本身功能的基础上给对象增加额外的新行为 2.定义:动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活 4.4.2 装饰模式的结构…...
C# 广播技术——发现局域网设备技术——
一广播技术应用 客户端发现与管理:软件可以通过广播消息来发现网络中的客户端,从而方便对客户端进行集中管理和监控。服务通知:向所有客户端广播重要的通知、更新或警告信息,确保客户端及时了解相关情况。资源共享与分配…...
【QA】windows和linux陷入系统调用后有什么区别?
最近被某面试官的这个问题拷打,当场脸烧起来… 首先讲讲系统调用: 系统调用是操作系统为调用者提供服务的接口,以便程序员聚焦于业务问题。分为文件操作,内存分配,进程管理等等。用户使用系统调用后会触发软中断&…...
Github 2024-11-01 开源项目月报 Top19
根据Github Trendings的统计,本月(2024-11-01统计)共有19个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目9TypeScript项目3JavaScript项目3Svelte项目1Jupyter Notebook项目1Ruby项目1HTML项目1Rust项目1Java项目1C++项目1Go项目1Python中的…...
Python实现深度学习模型预测控制(tensorflow)DL-MPC(Deep Learning Model Predictive Control
链接:深度学习模型预测控制 (如果认为有用,动动小手为我点亮github小星星哦),持续更新中…… 链接:WangXiaoMingo/TensorDL-MPC:DL-MPC(深度学习模型预测控制)是基于 P…...
Anki插件Export deck to html的改造
在Anki中进行复习时,每次只能打开一条笔记。如果积累了很多笔记,有时候会有将它们集中输出成一个pdf进行阅读的想法。Anki插件Export deck to html(安装ID:1897277426)就有这个功能。但是,这个插件目前存在…...
csdn 记载文章十分缓慢
现象:其它网站能够正常访问,但只要点击某个 csdn 页面就会等很久 (本文只针对 csdn 网页,其他网页出现类似情况可以同样处理) 产生这种现象的原因: 这种情况很有可能是在访问 CSDN 主页时,需要向…...
python通过pyperclip库操作剪贴板
pyperclip介绍 pyperclip是一个python库用于操作剪贴板,可以非常方便地将文本复制到剪贴板或从剪贴板获取文本。 通过pip进行安装:pip install pyperclip pyperclip的github地址 pyperclip使用 复制到剪贴板 import pypercliptext "Hello, Wo…...
LSTM——长短期记忆神经网络
目录 1.LSTM 工作原理 2.LSTM的代码实现 3.代码详解 LSTM(Long Short-Term Memory)是一种特殊的循环神经网络(RNN),用于解决长序列中的长期依赖问题。它通过引入门机制,控制信息的流入、保留和输出&…...
10进阶篇:运用第一性原理解答“是什么”类型题目
在667分析题题型中,关于“如何做”和“好处是什么”的题目,许多同学都能较好地运用前述的667作答地图开展答题,但是唯独在“是什么”类型题目(也可以叫做认识型题目),不知从何下手。这种题目通常要求我们理解、分析,并展望未来的发展方向,而结构化、逻辑清晰的答案往往…...
【elkb】索引生命周期管理
索引生命周期管理 Index lifecycle management(索引生命周期管理)是elasticsearch提供的一种用于自动管理索引的生命周期的功能。允许使用者定义索引的各个阶段,从创建至删除。并允许使用者在每个阶段定义索引需要执行的特定动作。这些动作包含索引创建,…...
江协科技STM32学习- P25 UART串口协议
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...
15分钟学 Go 第 22 天:包的使用
第22天:包的使用 欢迎来到Go语言的第22天!今天,我们将深入探讨如何创建和使用包。通过学习包的使用,你将能够更好组织你的代码,提高复用性和可维护性。 1. 包的概念 在Go语言中,包是代码的基本组织单位。…...
【Leecode】Leecode刷题之路第35天之搜索插入位置
题目出处 35-搜索插入位置-题目出处 题目描述 个人解法 思路: 1.依次遍历数组,看目标值是否在数组中 2.如果不在,将目标值插入数组(涉及到数组移动、扩容),返回下标代码示例:(Java…...
速盾:海外cdn高防
随着互联网的快速发展,网站的安全性和稳定性变得越来越重要。尤其是对于大型企业和电商平台来说,保护用户数据和维护网站稳定运行是至关重要的。为了应对日益增长的网络攻击和恶意访问,海外CDN高防服务成为了一种非常受欢迎的解决方案。 首先…...
图书管理系统(JDBC)
AdminUser是管理员类 NormalUser是用户类 AddOperation是增加图书类 BorrowOperation是借书类 DelOperation是删除图书类 ExitOperation是退出类 FindOperation是查找图书类 IOPeration是接口 ReturnOperation是还书类 ShowOperation是显示所有图书类 注意:…...
模板初阶及STL简介
目录 一.模板初阶 1.泛型函数 2.函数模板 1.函数模板概念 2.函数模板使用格式 3.函数模板的原理 4.函数模板的实例化 5.模板参数的匹配原则 3.类模板 1.类模板的定义格式 2.类模板的实例化 二.STL简介 1.什么是STL 2.STL的版本 3.STL的六大组件 4.如何学习STL …...
UE5 不同的编译模式下,module的组织形式
由于最近在琢磨UE5.4这个引擎,在学习过程中,碰到了一些非常有意思的事情,我在尝试把之前写的一些底层库搬到UE里面,比如底层库,网络库等等,我通过建立module,将这些库用源代码的方式整合进了UE5…...
【ms-swift 大模型微调实战】
安装环境 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simplepip install modelscope vllm ‘ms-swift[llm]’ -U 下载模型 modelscope download --model Qwen/Qwen2.5-7B-Instruct --local_dir ./Qwen2.5-7B-Instruct 微调 实验环境:…...
Linux:网络基础
计算机是人的工具,人需要协作,于是有了网络 专用服务器->专用计算机 局域网:随着计算机的数量增加,通过交换机和路由器连接计算机 广域网:将远隔千里的计算机都连在一起 协议 协议就是约定俗成 计算机之间用光信号…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...
《信号与系统》第 6 章 信号与系统的时域和频域特性
目录 6.0 引言 6.1 傅里叶变换的模和相位表示 6.2 线性时不变系统频率响应的模和相位表示 6.2.1 线性与非线性相位 6.2.2 群时延 6.2.3 对数模和相位图 6.3 理想频率选择性滤波器的时域特性 6.4 非理想滤波器的时域和频域特性讨论 6.5 一阶与二阶连续时间系统 6.5.1 …...
