设计模式06-结构型模式1(适配器/桥接/组合模式/Java)
#1024程序员节|征文#
4.1 适配器模式
- 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。
- 结构性模式的分类:
类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关。
对象结构型模式关心类与对象的组合,通过关联关系在一个类中定义另一个类的实例对象,然后通过该对象调用相应的方法。根据合成复用原则,在系统中尽量使用关联关系替代继承关系,因此大部分结构型模式都是对象结构型模式。
4.1.1 适配器模式的定义
1.动机:适配器可以使由于接口不兼容而不能交互的类可以一起工作,这就是适配器模式的模式动机。
2.定义:将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器
4.1.2 适配器模式的分析与实现
在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adaptor),它所包装的对象就是适配者(Adaptee),即被适配的类。适配器提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说,当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。
类适配器:
public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter extends Adaptee implements Target{@Overridepublic void request() {super.specialRequest();}
}
对象适配器:
public interface Target {public void request();
}
public class Adaptee {public void specialRequest() {System.out.println("特殊的请求方式");}
}
public class Adapter implements Target {private Adaptee adaptee;public void setAdaptee(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specialRequest();}
}
-
类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。
-
适配者类无法继承时,只能用对象适配器。
4.1.3 适配器模式的案例
现需要设计一个可以模拟各种动物行为的机器人,在机器人中定义了一系列方法,如机器人叫喊方法cry()、机器人移动方法move()等。如果希望在不修改已有代码的基础上使得机器人能够像狗一样叫,像狗一样跑,使用适配器模式进行系统设计。
public interface Robot {public void cry();public void move();
}
public class Dog {public void cry() {System.out.println("汪汪叫");}public void move() {System.out.println("快快跑");}
}
public class DogAdapter extends Dog implements Robot{public void cry(){super.cry();}public void move(){super.move();}
}
4.1.4 适配器模式的优缺点
优点 | 缺点 |
---|---|
1.将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构 | |
2.增加了类的透明性和复用性,提高了适配者的复用性 | |
3.灵活性和扩展性非常好,更换(增加)适配器,符合开闭原则 | |
4.类适配器模式:由于继承关系,置换一些适配者的方法很方便 | 不能适配多个适配类,每个目标类必须为接口,对于适配类为finial修饰的不可使用 |
5.对象适配器模式:可以把多个不同的适配者适配到同一个目标,还可以适配一个适配者的子类 | 在适配器中置换适配者类的某些方法比较麻烦 |
4.1.5 适配器模式的适用场景
-
系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码
-
创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作
4.1.6 双向适配器类
public class Adapter implements Target,Adaptee {private Target target;private Adaptee adaptee;public Adapter(Target target) {this.target = target; } public Adapter(Adaptee adaptee) {this.adaptee = adaptee; } public void request() {adaptee.specificRequest(); } public void specificRequest() {target.request(); }
}
4.2 桥接模式
4.2.1 桥接模式的定义
1.动机:如果系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使得两者可以独立扩展。桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多重继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效地控制了系统中类的个数。
2.定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
4.2.2 桥接模式的分析与实现
-
桥接模式中体现开闭原则、合成复用原则、里氏代换原则、依赖倒转原则等。
-
脱耦:桥接模式将抽象化和实现化之间的耦合解开,或者说是将强关联(继承)改换成弱关联,将两个角色之间的继承关系改为关联关系,使得两者可以独立变化。
public interface Implementor {public void implOperation(); } public class ConcreteImplementorA implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征A");} } public class ConcreteImplementorB implements Implementor{@Overridepublic void implOperation() {System.out.println("一个实体的维度1的特征B");} }public abstract class Abstracter {protected Implementor implementor;public void setImplementor(Implementor implementor) {this.implementor = implementor;}public abstract void operation(); } public class RefinedAbstracter extends Abstracter{@Overridepublic void operation() {System.out.println("一个实体维度2的特征");implementor.implOperation();} }
4.2.3 桥接模式的案例
public interface VideoFile {public void decode(String osType, String fileName);
}
public class MPEGFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".MPEG文件进行播放");}
}
public class WMVFile implements VideoFile{@Overridepublic void decode(String osType, String fileName) {System.out.println("位于" + osType + "操作系统的" + fileName + ".WMV文件进行播放");}
}
public abstract class OSVersion {protected VideoFile videoFile;public void setVideoFile(VideoFile videoFile) {this.videoFile = videoFile;}public abstract void play(String fileName);
}
public class LinuxVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Linux", fileName);}
}
public class WindowsVersion extends OSVersion{@Overridepublic void play(String fileName) {videoFile.decode("Windows", fileName);}
}
public class Main {public static void main(String[] args) {WMVFile wmvFile = new WMVFile();WindowsVersion windowsVersion = new WindowsVersion();windowsVersion.setVideoFile(wmvFile);windowsVersion.play("刺客五六七");MPEGFile mpegFile = new MPEGFile();LinuxVersion linuxVersion = new LinuxVersion();linuxVersion.setVideoFile(mpegFile);linuxVersion.play("喜羊羊与灰太狼");}
}
4.2.4 桥接模式的优缺点
优点 | 缺点 |
---|---|
1.分离抽象接口和实现部分 | 1.不容易正确识别俩个变化的维度 |
2.取代多继承,减少子类个数 | 2.关联关系在抽象层,设计难度大 |
3.扩展性,俩个维度均可扩展 |
4.2.5 桥接模式的适用场景
-
需要在抽象化和具体化之间增加更多的灵活性,扩展性,避免在两个层次之间建立静态的继承关系
-
一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立地进行扩展
-
不希望使用继承或因为多层继承导致系统类的个数急剧增加的系统
4.3 组合模式
4.3.1 组合模式的定义
1.动机:描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象。
2.定义:组合多个对象形成树形结构以表示“部分-整体”的结构层次。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性。
4.3.2 组合模式的分析与实现
- 组合模式用面向对象的方式来处理树形结构,它为叶子构件和容器构件提供了一个公共的抽象构件类,客户端可以针对该抽象类进行处理,而无需关心所操作的是哪种类型的对象。
- 使用聚合关系使得容器既可以添加叶子节点也可以添加容器
public abstract class Component {public abstract void add(Component component);public abstract void remove(Component component);public abstract Component getChild(int i);public abstract void method();
}public class Composite extends Component{private ArrayList<Component> list = new ArrayList<>();@Overridepublic void add(Component component) {list.add(component);}@Overridepublic void remove(Component component) {list.remove(component);}@Overridepublic Component getChild(int i) {return list.get(i);}@Overridepublic void method() {for (Component component : list) {component.method();}}
}public class Leaf extends Component{@Overridepublic void add(Component component) {throw new RuntimeException("叶子节点无法添加元素");}@Overridepublic void remove(Component component) {throw new RuntimeException("叶子节点无法删除元素");}@Overridepublic Component getChild(int i) {throw new RuntimeException("叶子节点无法获取元素");}@Overridepublic void method() {}
}
4.3.3 组合模式的案例
在操作系统中,一个文件夹中可能存放着图像文件,视频文件,文本文件,也可能存放其他的文件夹,而对不同类型的文件进行的浏览操作也不一样。
public abstract class AbstractFile {protected String fileName;public abstract void display();public abstract void add(AbstractFile file);public abstract void remove(AbstractFile file);
}
public class ImageFile extends AbstractFile{public ImageFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".png");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
public class TextFile extends AbstractFile{public TextFile(String fileName) {this.fileName = fileName;}@Overridepublic void display() {System.out.println("正在打开" + this.fileName + ".txt");}@Overridepublic void add(AbstractFile file) {throw new RuntimeException("无法添加文件");}@Overridepublic void remove(AbstractFile file) {throw new RuntimeException("无法删除文件");}
}
public class Folder extends AbstractFile{private ArrayList<AbstractFile> files;public Folder(String fileName) {files = new ArrayList<>();this.fileName = fileName;}@Overridepublic void display() {System.out.println("打开" + this.fileName + "文件夹");for (AbstractFile file : files) {file.display();}}@Overridepublic void add(AbstractFile file) {this.files.add(file);}@Overridepublic void remove(AbstractFile file) {this.files.remove(file);}
}
4.3.4 组合模式的优缺点
优点 | 缺点 |
---|---|
1.可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次 | 1.在增加新构件时很难对容器中的构件类型进行限制 |
2.客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构 | 2.不是所有方法在叶子节点中都可以使用 |
3.增加新的容器构件和叶子构件都很方便,符合开闭原则 |
4.3.5 组合模式的适用场景
-
在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待它们
-
在一个使用面向对象语言开发的系统中需要处理一个树形结构
-
在一个系统中能够分离出叶子对象和容器对象,而且它们的类型不固定,需要增加一些新的类型
4.3.6 组合模式的类型
- 透明组合模式
定义:抽象构件中声明了所有用于管理成员对象的方法,包括add()、remove(),以及getChild()等方法。
优点:确保所有的构件类都有相同的接口,客户端一致对待所有对象。
缺点:不够安全,因为叶子对象和容器对象在本质上是有区别的。
- 安全组合模式
定义:抽象构件Component中没有声明任何用于管理成员对象的方法,在Composite类中声明与实现这些方法
优点:优点是安全,对于叶子对象,客户端不可能调用到这些方法
缺点:不够透明,客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件
相关文章:
设计模式06-结构型模式1(适配器/桥接/组合模式/Java)
#1024程序员节|征文# 4.1 适配器模式 结构型模式(Structural Pattern)的主要目的就是将不同的类和对象组合在一起,形成更大或者更复杂的结构体。结构性模式的分类: 类结构型模式关心类的组合,由多个类…...
【损害和风险评估&坑洼】路面坑洼检测系统源码&数据集全套:改进yolo11-DCNV3
改进yolo11-DLKA等200全套创新点大全:路面坑洼检测系统源码&数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.24 注意:由于项目一直在更新迭代,上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可…...
GenAI 生态系统现状:不止大语言模型和向量数据库
自 20 个月前 ChatGPT 革命性的推出以来,生成式人工智能(GenAI)领域经历了显著的发展和创新。最初,大语言模型(LLMs)和向量数据库吸引了最多的关注。然而,GenAI 生态系统远不止这两个部分&#…...
gitlab 配置ssh keys
settings -- 终端配置: git config --global user.email "yxthotmail.cm" 配置gitlab 账号邮箱 git config --global user.name "xt.yao" 配置gitlab账号用户名 生成SSH key,输入命令ssh-keygen -t rsa,一直按回车…...
小程序开发实战:PDF转换为图片工具开发
目录 一、开发思路 1.1 申请微信小程序 1.2 编写后端接口 1.3 后端接口部署 1.4 微信小程序前端页面开发 1.5 运行效果 1.6 小程序部署上线 今天给大家分享小程序开发系列,PDF转换为图片工具的开发实战,感兴趣的朋友可以一起来学习一下!…...
我有两台120kw充电桩一天能赚多少钱
(当前是理想状态下,当然还要看场地费用,还有物业,变压器,等等) ———————————————————— ———————————————————— 要计算两台120kW充电桩能赚多少钱,我们…...
深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间
在 Android 开发中,xmlns (.xml的namespace)命名空间是一个非常重要的概念。通过引入不同的命名空间,可以使用不同的属性来设计布局、设置工具属性或者支持自定义视图等。除了 xmlns:tools 以外,还有很多常见的命名空间…...
stable-zero123模型构建指南
一、介绍 stabilityai出品,能够对有简单背景的物体进行三维视角图片的生成,简单来说也就是通过调整变换观察的视角生成对应视角的图片。 本项目通过comfyui实现。 二、容器构建说明 1. 部署ComfyUI (1)使用命令克隆ComfyUI g…...
算法题解记录32+++最长连续序列(百题筑基)
你们好,我是蚊子码农,好久不见。由于秋招求职的繁琐事情,我有很长一段时间没更新博客,希望我的粉丝们能够谅解。 秋招我拿到了一些offer,最终决定去一个主要做“网络安全”业务的公司工作,也许明天会更好&a…...
全球知名度最高的华人起名大师颜廷利:世界顶级思想哲学教育家
全国给孩子起名最好的大师颜廷利教授在其最新的哲学探索中,提出了《升命学说》这一前沿理论观点,该理论不仅深刻地回应了古今中外众多哲学流派和思想体系的精髓,还巧妙地融合了实用主义、理想主义以及经验主义的核心理念。通过这一独特的视角…...
Flink Rest API
REST API | Apache Flink Flink官网API 通过curl 或者Rest API工具测试web UI对应的接口返回信息 Flink 提交yarn任务 ./bin/flink run -t yarn-per-job historyServer ../bin/historyserver.sh start...
Zig 语言通用代码生成器:逻辑,冒烟测试版发布二
Zig 语言通用代码生成器:逻辑,冒烟测试版发布二 Zig 语言是一种新的系统编程语言,其生态位类同与 C,是前一段时间大热的 rust 语言的竞品。它某种意义上的确非常像 rust,尤其是在开发过程中无穷无尽抛错的过程&#x…...
mysql 通过GROUP BY 聚合并且拼接去重另个字段
我的需求: 我想知道同一个手机号出现几次,并且手机号出现在哪些地方。下面是要的效果。 源数据: CREATE TABLE bank (id bigint(20) unsigned NOT NULL AUTO_INCREMENT,user_id int(11) NOT NULL DEFAULT 0,tel varchar(255) COLLATE utf8mb4_unicode_…...
Java应用程序的测试覆盖率之设计与实现(一)-- 总体设计
一、背景 作为测试,如何保证开发人员提交上来的代码都被测试覆盖到,是衡量测试质量的一个重要指标。 本系列文章将要说一说,如何搭建一套测试覆盖率的系统。 包括以下内容: jacoco agent采集执行覆盖率数据jacoco climaven集成jacoco:jacoco-maven-pluginant集成jacoco:…...
Unity C#脚本的热更新
以下内容是根据Unity 2020.1.0f1版本进行编写的 目前游戏开发厂商主流还是使用lua框架来进行热更,如xlua,tolua等,也有的小游戏是直接整包更新,这种小游戏的包体很小,代码是用C#写的;还有的游戏就是通过…...
监督学习之逻辑回归
逻辑回归(Logistic Regression) 逻辑回归是一种用于二分类(binary classification)问题的统计模型。尽管其名称中有“回归”二字,但逻辑回归实际上用于分类任务。它的核心思想是通过将线性回归的输出映射到一个概率值…...
深度优先算法(DFS)洛谷P1683-入门
虽然洛谷是有题解的,但是你如果直接看得懂题解,你也不会来看这篇文章.. 这些代码均是我记录自身成长的记录,有写的不好的地方请谅解! 先上代码: #include <iostream> #include <vector> #include<iomanip> #include<cstdio&…...
Python数据分析基础
本文介绍了Python在数据分析中的应用,包括数据读取、清洗、处理和分析的基本操作。通过使用Pandas和Numpy库,我们可以高效地处理大量数据,并利用Matplotlib和Seaborn库进行数据可视化。 1. 引言 Python因其简洁的语法和强大的库支持&#x…...
《企业自设2-软件测试》线下课day3: 006扩展虚拟机
1.win11 修改hosts无权限 分别再cmd终端输入以下两行代码: C:\Windows\System32\drivers\etcnotepad hosts 2.先保存快照!!! 3.关闭虚拟机,将内存,CPU进行修改 就是再这个位置修改: 4.运…...
配置和排查 Lombok 在 IDEA 中使用的详细步骤
在日常开发中,Java 代码常常需要大量的样板代码,比如 getter、setter、toString 等方法。Lombok 是一个 Java 库,可以通过注解的方式,自动生成这些常见的代码,从而让代码更加简洁、清晰。比如,我们可以通过…...
JavaWeb合集18-接口管理Swager
十八、接口管理 1、Swager 使用Swagger你只需要按照它的规范去定义接口及接口相关的信息,就可以做到生成接口文档,以及在线接口调试页面。 官网: https://swagger.io/ Knife4j是为Java MVC框架集成Swagger生成Api文档的增强解决方案。 <dependency&g…...
背包九讲——二维费用背包问题
目录 二维费用背包问题 问题描述: 解决方法: 方法一: 代码实现: 方法二: 代码实现: 背包问题第五讲——二维费用背包问题 背包问题是一类经典的组合优化问题,通常涉及在限定容量的背包中…...
【mysql进阶】4-7. 通用表空间
通⽤表空间 - General Tablespace 1 通⽤表空间的作⽤和特性? ✅ 解答问题 通⽤表空间是使⽤ CREATE tablespace 语法创建的共享InnoDB表空间 通⽤表空间能够存储多个表的数据,与系统表空间类似也是共享表空间; 服务器运⾏时会把表空间元数…...
2024 年互联网大厂 1300 多道 JAVA 面试题汇总,包含了程序员的所有技术点
作为一个 Java 程序员,你平时总是陷在业务开发里,每天噼里啪啦忙敲着代码,上到系统开发,下到 Bug 修改,你感觉自己无所不能。然而偶尔的一次聚会,你听说和自己一起出道的同学早已经年薪 50 万,而…...
【开源免费】基于SpringBoot+Vue.JS在线文档管理系统(JAVA毕业设计)
本文项目编号 T 038 ,文末自助获取源码 \color{red}{T038,文末自助获取源码} T038,文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…...
Linux资源与网络请求
参数说明: d : 改变显示的更新速度,或是在交谈式指令列( interactive command)按 sq : 没有任何延迟的显示速度,如果使用者是有 superuser 的权限,则 top 将会以最高的优先序执行c : 切换显示模式,共有两种模式&#…...
RPA技术重塑企业自动化的未来
1. RPA定义与原理 1.1 机器人流程自动化(RPA)概念 机器人流程自动化(Robotic Process Automation,简称RPA)是一种软件技术,通过模拟人类用户在计算机界面上的操作来执行重复性的业务流程任务。RPA软件机器人能够自动执行基于规则…...
使用RabbitMQ实现延迟消息的完整指南
在分布式系统中,消息队列通常用于解耦服务,RabbitMQ是一个广泛使用的消息队列服务。延迟消息(也称为延时队列或TTL消息)是一种常见的场景应用,特别适合处理某些任务在一段时间后执行的需求,如订单超时处理、…...
阿里员工:阿里工作7年至少得P7吧,快的都P8了,年薪100W是正常的,80才算及格...
上一篇:一线体面男的收入 年薪64W的阿里蚂蚁员工爆料:在阿里,工作7年至少得P7,快的都P8了,年薪100W才正常,80分才算及格。 其实,在大厂工作,听起来风光无限,但个中滋味&a…...
Django进一步掌握(10月22日)
一、请求响应对象 请求对象request 响应对象HttpResponse 二、HttpResponse常用属性 status设置HTTP响应状态码 status_code查询HTTP响应状态码 content_type设置响应的类型 write()写入响应内容 三、重定向 1、实现URl访问的重定向 (1)使用Ht…...
网站建设组织/淘宝店铺如何推广
解决方法一:RequestMapping(value"/getphone",produces "text/plain;charsetutf-8") /**输入手机号码后判断手机号是否存在*/ RequestMapping(value"/getphone",produces "text/plain;charsetutf-8") ResponseBody publi…...
中国建筑工程网施工组织设计/哈尔滨seo服务
一、前言 在配置springboot的配置的时候突然看到时间是Duration来配置的,上源码看到这样一个方法 /*** Obtains a {code Duration} from a text string such as {code PnDTnHnMn.nS}.* <p>* This will parse a textual representation of a duration, includ…...
西安网站建设咪豆互联/互联网营销课程体系
此函数允许创建方向强度直方图,也称为“风玫瑰”。这个工具可以用来表示这种图形。 This function allows to create a Direction-intensity histogram, also known as “Wind Roses”. This tool can be used for representing this kind of graphics. 它还能够将…...
营销型网站设计建设公司/福州网站建设策划
Android设计模式系列(10)--SDK源码之原型模式 Android设计模式系列(9)--SDK源码之适配器模式 Android设计模式系列(8)--SDK源码之工厂方法模式 Android设计模式系列(7)--SDK源码之命令模式 Android设计模式系列(6)--SDK源码之享元模式 Android设计模式系列(5)--SDK源码之备忘录…...
图片设计师网站/百度数据库
SSH(安全外壳)是用于基于Linux的系统,路由器,交换机,防火墙,设备和其他资产的最常见的远程管理协议。尽管SSH守护程序提供了出色的强化功能,以增强您的身份验证方法和访问控制,但SSH…...
iapp用网站做软件代码/什么是软文推广
欢迎观看Illustrator教程,小编带大家学习Illustrator2022的基本工具和使用技巧,了解如何在 Illustrator 中创建、编辑以及应用自定义渐变。 Illustrator 提供多种着色方式, 让您可以创造性地运用色彩,包括在图稿上应用渐变。渐变…...