【设计模式】结构型设计模式

结构型设计模式

文章目录

  • 结构型设计模式
    • 一、概述
    • 二、适配器模式(Adapter Pattern)
      • 2.1 类适配器模式
      • 2.2 对象适配器模式
      • 2.3 接口适配器模式
      • 2.4 小结
    • 三、桥接模式(Bridge Pattern)
    • 四、装饰器模式(Decorator Pattern)
    • 五、组合模式(Composite Pattern)
    • 六、外观模式(Facade Pattern)
    • 七、享元模式(Flyweight Pattern)
    • 八、代理模式(Proxy Pattern)
    • 九、依赖注入模式 *(Dependency Injection)
    • 十、流接口模式 *(Fluent Interface)

一、概述

这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 装饰器模式(Decorator Pattern)
  • 组合模式(Composite Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)
  • 依赖注入模式 *(Dependency Injection)
  • 流接口模式 *(Fluent Interface)

二、适配器模式(Adapter Pattern)

  1. 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
  2. 主要分为三类:类适配器模式对象适配器模式接口适配器模式

2.1 类适配器模式

Adapter类,通过继承 src类,实现 dst 类接口,完成src->dst的适配。

以手机充电器为例子:

在这里插入图片描述

充电器本身相当于Adapter,220V交流电相当于src (即被适配者),dst(即目标)是5V直流电

2.2 对象适配器模式

  1. 基本思路和类的适配器模式相同,只是将Adapter类作修改,不是继承src类,而是持有src类的实例,以解决兼容性的问题。 即:持有 src类,实现 dst 类接口,完成src->dst的适配
  2. 根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系
  3. 对象适配器模式是适配器模式常用的一种
public class VoltageAdapter2 implements Voltage5 {
    private Voltage220 voltage220; //持有Voltage220对象,不是继承了
}

2.3 接口适配器模式

当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。在使用Java做页面监听时经常会碰到对应适配类。

2.4 小结

  1. 三种命名方式,是根据 src是以怎样的形式给到Adapter(在Adapter里的形式)来命名的。
    1. 类适配器:以类给到,在Adapter里,就是将src当做类,继承
    2. 对象适配器:以对象给到,在Adapter里,将src作为一个对象,持有
    3. 接口适配器:以接口给到,在Adapter里,将src作为一个接口,实现
  2. Adapter模式最大的作用还是将原本不兼容的接口融合在一起工作。
  3. 实际开发中,实现起来不拘泥于这三种经典形式

三、桥接模式(Bridge Pattern)

  1. 桥接模式(Bridge 模式)是指:是将抽象部分与它的具体实现部分分离,使它们都可以独立地变化。
  2. Bridge 模式基于类的最小设计原则,通过组合/聚合的方式建立两个类之间的联系,而不是继承。但又类似于多重继承方案,但是多重继承方案往往违背了类的单一职责原则,其复用性较差,桥接模式是比多重继承更好的替代方案。桥接模式的核心在于解耦抽象和实现。

在这里插入图片描述

  1. Client 类:桥接模式的调用者
  2. 抽象类(Abstraction) :维护了 Implementor / 即它的实现类 ConcreteImplementorA…, 二者是聚合关系, Abstraction充当桥接类
  3. RefinedAbstraction : 是 Abstraction 抽象类的子类
  4. Implementor : 行为实现类的接口
  5. ConcreteImplementorA /B :行为的具体实现类
  6. 从 UML 图:这里的抽象类和接口是聚合的关系,其实是调用和被调用关系

上面概念比较抽象,这里以手机为例:

  1. 首先有需求,手机可以按品牌分:HuaWei、Vivo、XiaoMi,不同品牌对应着不同的应用商城
  2. 业务需求变更,对于手机型号有了区分,分为A、B、C型,不按桥接模式设计,则需要多重继承实现功能全排序,不同品牌对应不同型号共9个实现
  3. 按桥接模式设计,新建一个桥接抽象类为Phone,其实现类分别为A、B、C型,有不同的功能,通过聚合关系,将品牌实现接口聚合到Phone抽象类中,这样只需新增3个实现类;而手机的型号以及品牌又可以区分开来,分别运用其不同特别功能

常见应用场景

  1. JDBC 驱动程序
  2. 银行转账系统
    • 转账分类: 网上转账,柜台转账,AMT 转账
    • 转账用户类型:普通用户,银卡用户,金卡用户
  3. 消息管理
    • 消息类型:即时消息,延时消息
    • 消息分类:手机短信,邮件消息,QQ 消息…

四、装饰器模式(Decorator Pattern)

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。

典型的应用就是jdk中IO流的应用,FilterInputStream 就是一个装饰者,BufferInputStream是具体的实现类,通过组合的关系,使得输入流有了缓冲的功能,而又无需修改原有inputStream代码。

在这里插入图片描述

五、组合模式(Composite Pattern)

组合模式就运用了树形结构,该模式的核心思想是:将多个对象组合成树形结构,以此结构来表示“整体-部分”之间的层次关系。

在这里插入图片描述

  1. 抽象根节点(Component):定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性
  2. 树枝节点(Composite):定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一 个树形结构
  3. 叶子节点(Leaf):叶子节点对象,其下再无分支,是系统层次遍历的最小单位

应用场景:

  1. 组合-部分整体场景:将多个对象组合成一个整体,并且整体与部分是一致对待的。比如树形菜单、文件夹和文件等
  2. 递归结构场景:处理递归的数据结构。比如文件和目录的关系就是递归的
  3. 规则场景:当需要处理的对象具有明显的层次结构时,可以考虑使用组合模式。比如,企业中不同职位的员工,每个职位的员工都有一些共同的属性(比如姓名、公司邮件地址),但也有一些不同的属性(比如职位、薪水等)
  4. 任务分解场景:将一个大任务分解为多个小任务,然后再将小任务组合起来,形成一个任务树。这种情况下,可使用组合模式对任务进行建模
  5. GUI控件场景:GUI控件通常可以嵌套在其他控件中,并且用户可以在控件中插入其他控件,组合模式适用于GUI控件的场景

组合模式适用于处理树形结构的场景,将一个对象的部分和整体看作一样,形成一个树形结构。在需要统一处理整个树形结构时,可以考虑使用组合模式。

六、外观模式(Facade Pattern)

外观模式(Facade),也叫过程模式:外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口。

外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节。这个模式我们平时就会使用,比如调用交易接口,交易接口中会再去调用其他各个接口。或者MVC模式下我们写的Controller,即对外暴露接口,前端开发无需关心后端干了什么。

在这里插入图片描述

  1. 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
  2. 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个 Facade 类,来提供遗留系统的比较清晰简单的接口,让新系统与 Facade 类交互,提高复用性
  3. 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的

七、享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern) 也叫 蝇量模式: 运用共享技术有效地支持大量细粒度的对象。

享元模式经典的应用场景就是池技术了,String 常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式

在这里插入图片描述

  1. FlyWeight 是抽象的享元角色, 他是产品的抽象类, 同时定义出对象的外部状态和内部状态(后面介绍) 的接口或实现
  2. ConcreteFlyWeight 是具体的享元角色,是具体的产品类,实现抽象角色定义相关业务
  3. UnSharedConcreteFlyWeight 是不可共享的角色,一般不会出现在享元工厂
  4. FlyWeightFactory 享元工厂类,用于构建一个池容器(集合), 同时提供从池中获取对象方法,这个一般被设计为单例模式

内部状态是不会变化的,可以被多个对象共享,而外部状态会随着对象的使用而改变。比如,连接池中的连接对象,保存在连接对象中的用户名、密码、连接URL等信息,在创建对象的时候就设置好了,不会随环境的改变而改变,这些为内部状态。而当每个连接要被回收利用时,我们需要将它标记为可用状态,这些为外部状态。

八、代理模式(Proxy Pattern)

代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

在这里插入图片描述

代理模式有不同的形式, 主要有三种 静态代理动态代理 (JDK 代理、接口代理)和 Cglib 代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于动态代理的范畴)。最经典的运用即Spring的AOP。

九、依赖注入模式 *(Dependency Injection)

依赖注入(Dependency Injection)是控制反转(Inversion of Control)的一种实现方式。

我们先来看看什么是控制反转。当调用者需要被调用者的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例,但在这里,创建被调用者的工作不再由调用者来完成,而是将被调用者的创建移到调用者的外部,从而反转被调用者的创建,消除了调用者对被调用者创建的控制,因此称为控制反转。

要实现控制反转,通常的解决方案是将创建被调用者实例的工作交由 IoC 容器来完成,然后在调用者中注入被调用者(通过构造器/方法注入实现),这样就实现了调用者与被调用者的解耦,该过程被称为依赖注入。依赖注入不是目的,它是一系列工具和手段,最终的目的是帮助开发出松散耦合(loose coupled)、可维护、可测试的代码和程序。这条原则的做法是大家熟知的面向接口,或者说是面向抽象编程。典型应用案例即Spring中使用@Autowize 注解实现属性注入。

个人感觉这种模式和注册模式类似,都是通过统一容器收纳注册对象,调用方直接通过注册容器调用接口,具体实现类则由容器返回。故不再对注册模式分析。

十、流接口模式 *(Fluent Interface)

在软件工程中,流接口(Fluent Interface)是指实现一种面向对象的、能提高代码可读性的 API 的方法,其目的就是可以编写具有自然语言一样可读性的代码,我们对这种代码编写方式还有一个通俗的称呼 —— 方法链。

最常见的就是Lombak注解中,@Builder 或者 @Accessors(chain=true) 开启链式编程,即可通过方法链调用的方式设置实体类的属性。

// 用简洁的方式实例化实体类并完成赋值操作,而无需多行不断调用set方法
XUser xUser = XUser.builder().userId(1).userName("AAAAA").build();

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《微信小程序开发从入门到实战》学习二十一

3.3 开发创建投票页面 3.3.9 使用picker选择器组件 使用picker选择器组件增加一个设置截止时间的功能。picker是一个从底部弹出的滚动选择器组件。picker通用属性如下: mode 选择器类型(selector、multiSelector、time、date、region) disabled …

USB转CAN的使用说明

前言 USB转CAN是将 TTL 信号转换为 CAN 信号的模块。采用串口作为嵌入式系统的接口,数据传输简单,无需要学习 CAN 协议,缩短开发周期,降低开发成本。模块兼容 3.3V、5V 电源,搭载一个 32 位的 STM32 处理芯片和一个 C…

buildadmin+tp8表格操作(7.1)表格的事件监听(el-table中的事件)

因为buildAdmin是封装的 el-table的组件,所以el-table中的事件, 也是可以使用的, 两者有几个事件是有共同的(比如 双击事件), 这时可以根据自己的需要自行选择 以下代码是 buildadmin 使用 el-table中的事…

键盘映射笔记

dumpkeys命令用于显示当前系统中定义的键盘映射表。它可以帮助用户查看和理解系统中的键盘布局和键盘映射规则。 当用户执行dumpkeys命令时,它会读取系统中的键盘映射表文件(通常是/etc/keymaps或/etc/console/boottime.kmap.gz),…

麒麟KYLINOS2303系统上禁用新功能介绍页面

原文链接:麒麟KYLINOS2303系统上禁用新功能介绍页面 hello,大家好啊,今天给大家带来一篇在麒麟KYLINOS2303系统上禁用新功能介绍页面的文章,在我们安装完系统登录后,会发现有新功能介绍这个界面,我们可以通…

buildadmin+tp8表格操作(8) 表格下方添加 合计行

表格的下方可以自定义添加一个合计行&#xff0c;如果有其它的需求&#xff0c; 我们可以添加我们自已需要的行&#xff0c; 并不局限于合计行 以上就可以给表格的最下方添加一个合计行了 完整代码如下 <template><div class"default-main ba-table-box"&…

Blender烘焙AO操作及对应的python代码

&#xff08;一&#xff09;Blender软件操作 1. 导入模型&#xff08;这里省略&#xff09; 2. 材质设置 模型使用的所有材质都需要删除Surface Shader&#xff0c;没有其他多余的计算&#xff0c;可以大量缩短烘焙时间。删除之后的只留下一个材质输出节点&#xff0c;如图所…

Vatee万腾携手Wiki EXPO 2023悉尼峰会 共谱辉煌未来

悉尼&#xff0c;这座充满活力和创新的城市&#xff0c;即将成为全球商业的焦点。2023年11月16日&#xff0c;由WikiEXPO主办的Wiki Finance Expo Sydney 2023在悉尼马丁广场1号富丽敦酒店隆重开幕&#xff0c;这场金融博览会是澳大利亚今年规模最宏大、备受期待的金融科技盛会…

网上被吹爆的Spring Event事件订阅有缺陷,不要用

Spring Event事件订阅框架&#xff0c;被网上一些人快吹上天了&#xff0c;然而我们在新项目中引入后发现&#xff0c;这个框架缺陷很多&#xff0c;玩玩可以&#xff0c;千万不要再公司项目中使用。还不如自己手写一个监听者设计模式&#xff0c;那样更稳定、可靠。 之前我已…

电磁场与电磁波part5--均匀平面波在无界空间的传播

目录 1、相位速度 2、波阻抗 3、理想介质中均匀平面波的传播特点 4、色散现象 5、导电媒质中均匀平面波的传播特点 6、趋肤效应 7、电磁波的极化 1、相位速度 电磁波的等相位面在空间中的移动速度&#xff08;相速&#xff09; 在自由空间&#xff08;自由空间的光速&a…

UE5 - ArchvizExplorer - 数字孪生城市模板 - 功能修改

数字孪生项目&#xff0c;大多是双屏互动&#xff0c;而非下方菜单点击&#xff0c;所以要做一番改造 参考&#xff1a;https://blog.csdn.net/qq_17523181/article/details/133853099 1. 去掉提示框 打开BP_MasterMenu_Widget&#xff0c;进入EventGraph&#xff0c;断开Open…

仅需1分钟,搭建一个你自己的工具站

{alert type"info"} 站长工具在工作中应该会有很多人使用&#xff0c;比如说 JSON格式化&#xff0c;UUID生成器&#xff0c;密码生成、URL编码等 今天给大家分享一个英文版的IT-TOOL的搭建教程。 是个开源的项目&#xff0c;地址&#xff1a;https://github.com/Cor…

JZM-D30室温探针台技术参数

概况&#xff1a; JZM-D30室温探针台的诸多设计都是专用的&#xff0c;探针台的配置主要是根据用户的需求进行选配及设计。例如&#xff0c;要求的磁场型号&#xff0c;电源型号&#xff0c;磁场值&#xff0c;样品台的尺寸等&#xff0c;除此之外&#xff0c;该探针台和我司自…

el-tree结合el-switch实现状态切换

<template><div><el-col :span"24"><el-card class"tree-card"><div class"sketch_content selectFile"><span class"span_title">组织列表 </span><div style"display: flex; jus…

【文末送书】计算机网络 | IO多路转接技术 | poll/epoll详解

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

DAY59 503.下一个更大元素II + 42. 接雨水

503.下一个更大元素II 题目要求&#xff1a; 给定一个循环数组&#xff08;最后一个元素的下一个元素是数组的第一个元素&#xff09;&#xff0c;输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序&#xff0c;这个数字之后的第一个比它更大的数&am…

DDD落地:从美团抽奖平台,看DDD在大厂如何落地?

尼恩说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 谈谈你的DDD落地经验&#xff1f; 谈谈你对DDD的理解&#xff…

【深入Scrapy实战】从登录到数据解析构建完整爬虫流程

文章目录 1. 写在前面2. 抓包分析3. Scrapy提交登陆请求4. 列表与详情页面数据解析5. 中间件Middleware配置 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xf…

迈巴赫S480升级镀铬中网 480秒变680

迈巴赫S480的首选项目&#xff0c;就是前杠格栅升级了&#xff0c;只需要替换前杠下方的三个格栅中网&#xff0c;就可以直接升级成迈巴赫S680的外形&#xff0c;立马提升了两个档次。

SAP ABAP给指定用户增加SAP ALL权限

下面的例子是给指定用户增加SAP ALL的权限ABAP代码&#xff0c;增加指定权限对像的没研究&#xff0c;只能自己看了。这应该是SAP权限的无限破解了吧。 例子中SAP*,是当前系统中有SAP_ALL权限的一个用户&#xff0c;用来参考使用的&#xff0c;根据实际系统用的最大权限用户&a…