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

结构型设计模式

文章目录

  • 结构型设计模式
    • 一、概述
    • 二、适配器模式(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();

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

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

相关文章

2 Redis的高级数据结构

1、Bitmaps 首先,最经典的应用场景就是用户日活的统计,比如说签到等。 字段串:“dbydc”,根据对应的ASCII表,最后可以得到对应的二进制,如图所示 一个字符占8位(bit),…

操作系统基础操作

操作系统的启动 体系结构概念 CPU、I/O、内存-通过总线连接 操作系统一开始存放时没有放在内存里,而是当在DISK中,由BIOS提供相应支持 DISK:存放OSBIOS:基本I/O处理系统(计算机开机时可以让系统检测各种外设&#…

idea 环境搭建及运行java后端源码

1、 idea 历史版本下载及安装 建议下载和我一样的版本,2020.3 https://www.jetbrains.com/idea/download/other.html,idea分为专业版本(Ultimate)和社区版本(Community),前期可以下载专业版本…

“开源 vs. 闭源:大模型的未来发展趋势预测“——探讨大模型未来的发展方向

文章目录 每日一句正能量前言什么是大模型的开源与闭源开源与闭源的定义和特点开源的意义开源和闭源的优劣势比较不同的大模型企业,开源、闭源的策略不尽相同。企业在开发垂类模型时选择开源还是闭源大模型开源vs 闭源:两者并非选择题后记 每日一句正能量…

多模态大模型训练数据集汇总介绍

RefCOCO、RefCOCO、RefCOCOg 这三个是从MS-COCO中选取图像得到的数据集,数据集中对所有的 phrase 都有 bbox 的标注。 RefCOCO 共有19,994幅图像,包含142,209个引用表达式,包含50,000个对象实例。RefCOCO 共有19,992幅图像,包含1…

【开源】基于Vue和SpringBoot的中小学教师课程排课系统

项目编号: S 053 ,文末获取源码。 \color{red}{项目编号:S053,文末获取源码。} 项目编号:S053,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 角色管理模块2.2 课程档案模块2.3 排…

【前端学java】Java中的异常处理(15)完结

往期回顾: 【前端学java】JAVA开发的依赖安装与环境配置 (0)【前端学java】java的基础语法(1)【前端学java】JAVA中的packge与import(2)【前端学java】面向对象编程基础-类的使用 (…

STM32:时钟树原理概要

在一般情况下只要在CubeIDE中将RCC下的高速时钟源设置成晶振,随后在时钟配置中把HCLK设置到最大频率(比如STM32F103的最高频率是72MHZ ),CubeIDE就会帮我们自动调节其它参数到合适的值。这样我们芯片就可以全速运行了。 一、时钟信…

C++函数

转载知呼大佬06 - C函数 - 知乎 (zhihu.com) 06 - C函数 本期我们讨论的是 C 中的函数。 函数到底是什么呢,函数就是我们写的代码块,被设计用来执行特定的任务,以后我们学习 class 类的时候,这些块会被称为方法,但是…

windows排除扫描文件夹

搜索防火墙和网络保护 点击病毒和威胁防护 往下拉,找到排除项 添加排除项

MySQL InnoDB 引擎底层解析(三)

6.3.3. InnoDB 的内存结构总结 InnoDB 的内存结构和磁盘存储结构图总结如下: 其中的 Insert/Change Buffer 主要是用于对二级索引的写入优化,Undo 空间则是 undo 日志一般放在系统表空间,但是通过参数配置后,也可以用独立表空 间…

【C++上层应用】2. 预处理器

文章目录 【 1. #define 预处理 】【 2. #ifdef、#if 条件编译 】2.1 #ifdef2.2 #if2.3 实例 【 3. # 和 ## 预处理 】3.1 # 替换预处理3.2 ## 连接预处理 【 4. 预定义宏 】 预处理器是一些指令,指示编译器在实际编译之前所需完成的预处理。 所有的预处理器指令都是…

分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测

分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测 目录 分类预测 | Matlab实现基于PSO-SDAE粒子群优化算法优化堆叠去噪自编码器的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现基于PSO-SDAE粒子群优化算法…

Flutter笔记:使用相机

Flutter笔记 使用相机 作者:李俊才 (jcLee95):https://blog.csdn.net/qq_28550263 邮箱 :291148484163.com 本文地址:https://blog.csdn.net/qq_28550263/article/details/134493373 【简介】本文介绍在 Fl…

听GPT 讲Rust源代码--src/librustdoc

题图来自 Why is building a UI in Rust so hard? File: rust/src/librustdoc/core.rs 在Rust中,rust/src/librustdoc/core.rs文件的作用是实现了Rustdoc库的核心功能和数据结构。Rustdoc是一个用于生成Rust文档的工具,它分析Rust源代码,并生…

git基本操作(配图超详细讲解)

个人主页:Lei宝啊 愿所有美好如期而遇 目录 创建git本地仓库 配置仓库 认识工作区,暂存区,版本库 修改文件 版本回退 撤销修改 删除文件 创建git本地仓库 要提前说的是,仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂…

linux网络——HTTPS加密原理

目录 一.HTTPS概述 二.概念准备 三.为什么要加密 四.常⻅的加密⽅式 1.对称加密 2.⾮对称加密 五.数据摘要,数字签名 六.HTTPS的加密过程探究 1.方案一——只使用对称加密 2.方案二——只使⽤⾮对称加密 3.方案三——双⽅都使⽤⾮对称加密 4.方案四——⾮…

stack和queue简单实现(容器适配器)

容器适配器 stack介绍stack模拟实现queue 介绍queue模拟实现deque stack介绍 stack模拟实现 以前我们实现stack,需要像list,vector一样手动创建成员函数,成员变量。但是stack作为容器适配器,我们有更简单的方法来实现它。 可以利用模板的强大…

go语言学习之旅之Go 语言指针

学无止境,今天继续学习go语言的基础内容 Go语言支持指针,允许你在程序中直接操作变量的内存地址。指针存储了变量的内存地址,通过指针,你可以直接访问或修改该地址上的值。 学习过c语言的一定知道指针 定义指针 在Go语言中&…

AC修炼计划(AtCoder Beginner Contest 329)

传送门:Sky Inc, Programming Contest 2023(AtCoder Beginner Contest 329) - AtCoder A,B,C,D 这四道题比较简单,就不多叙述。 E - Stamp 这题是一道比较…