编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 05.静态代理设计模式
  • 06.动态代理设计模式
  • 07.适配器模式设计思想
  • 08.装饰者模式设计思想
  • 09.外观模式设计思想
  • 10.桥接模式设计思想
  • 11.组合模式设计思想
  • 12.享元模式设计思想

结构型设计模式

目录

  • 05.静态代理设计模式
  • 06.动态代理设计模式
  • 07.适配器模式设计思想
  • 08.装饰者模式设计思想
  • 09.外观模式设计思想
  • 10.桥接模式设计思想
  • 11.组合模式设计思想
  • 12.享元模式设计思想

05.静态代理设计模式

01.静态代理模式基础

由来和背景:在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。比如以下场景就适合用代理模式

  1. 个人,通过中介来找房东发布的租房。
  2. 乘客,通过火车站来购买铁路局的车票。
  3. 客户,通过VPN代理来翻墙查阅国外资料。

一句话概括就是:代理模式(Proxy Pattern) :给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

静态代理使用场景:监控、统计、鉴权,日志等场景。附加功能与业务功能解耦,放到代理类统一处理,让程序员只需要关注业务方面的开发!

02.静态代理原理与实现

实现模式

  1. 首先创建一个接口(代理都是面向接口的),
  2. 创建具体实现类来实现这个接口,
  3. 创建一个代理类同样实现这个接口,不同之处在于具体实现类的方法中需要将接口中定义的方法的业务逻辑功能实现,而代理类中的方法只要调用具体类中的对应方法即可,这样我们在需要使用接口中的某个方法的功能时直接调用代理类的方法即可,将具体的实现类隐藏在底层。

举一个实际案例

  1. 定义用户找房子的需求接口
  2. 创建用户找房子具体实现类
  3. 创建一个代理中介,委托中介去找房子

03.静态代理分析

代理模式包含如下角色:

  1. Subject: 抽象主题角色
  2. Proxy: 代理主题角色
  3. RealSubject: 真实主题角色

04.代理模式优势

  1. 使用静态代理来降低耦合。比如,邮件发送的接口 MailSender,以及一个实现该接口的具体类 RealMailSender。可以在不修改 RealMailSender 类的情况下,为邮件发送操作添加额外的功能。这样,RealMailSender 类和 MailSenderProxy 类之间的耦合度降低,客户端只需要与 MailSender 接口进行交互,而不需要关心具体的实现类。
  2. 静态代理可以用于保护真实对象的使用权限。在真正需要显示图像时,真实对象才会被加载和显示,从而保护了真实对象的使用权限。

05.静态代理不足

  1. 静态代理缺乏灵活说明
  2. 代码复用难,会导致代码庞大
  3. 难以动态添加功能
  4. 静态代理无法满足多态性

06.动态代理设计模式

01.为何要动态代理

一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色(委托类),该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

02.动态代理的概念

动态代理是指:代理类是在运行期间生成的,也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成的类字节码,并加载到JVM中。

动态代理定义:给某个对象提供一个代理对象,并由代理对象控制对于原对象的访问,即客户不直接操控原对象,而是通过代理对象间接地操控原对象。

03.动态代理的实现

代理模式的角色分四种:

  1. 主题接口:Subject,是委托对象和代理对象都共同实现的接口,即代理类的所实现的行为接口。
  2. 目标对象:ReaSubject,是原对象,也就是被代理的对象。
  3. 代理对象:Proxy,是代理对象,用来封装真是主题类的代理类。
  4. 客户端:使用代理类和主题接口完成一些工作。

04.动态代理案例

组成元素:

  1. 抽象类接口
  2. 被代理类(具体实现抽象类接口的类)
  3. 动态代理类,实际调用被代理类的方法和属性

动态代理有两种实现方式:

  1. 基于接口动态代理。一种常见的动态代理方式,它通过实现Java的Proxy类和InvocationHandler接口来实现。
  2. 基于类动态代理。另一种常见的动态代理方式,它使用第三方库或框架来实现。在Java中,常用的类动态代理库包括CGLIB。

05.动态代理思想和原理

动态代理实现机制,主要是通过关键类Proxy和InvocationHandler来实现的。

  1. 创建InvocationHandler处理器对象,主要作用是通过实现方法,调用从代理类到委托类的分派转发。
  2. 通过Proxy创建代理对象,传入指定 ClassLoader 对象和一组 interface 来创建动态代理类,里面实现是通过反射去动态创建对象。

07.适配器模式设计思想

01.适配器模式基础

什么叫做适配器模式?用来做适配,将不兼容的接口转化成兼容的接口,例子就是 USB 转接头充当适配器,把两种不兼容的接口,通过转接变得可以一起工作。

简单来说,用于事后补救措施,项目代码后期,想让不想关的类,变成可以一起工作。可以作为类结构型模式,也可以作为对象结构型模式。

适配器模式思考?不要强行适配,设计前期就要考虑到兼容性,以减少对适配器依赖!

02.适配器模式实现

适配器模式两种实现方式:

  1. 类的适配器。通过继承来实现
  2. 对象的适配器。通过组合来实现

03.适配器模式分析

类适配器是一种结构型设计模式,它允许将一个类的接口转换为另一个客户端所期望的接口。通过继承原始类和实现目标接口,类适配器使得原始类的接口与目标接口兼容。

对象适配器是适配器模式的一种变体,它通过组合(而不是继承)原始类和目标接口来实现适配器功能。在对象适配器中,适配器类持有一个原始类的实例,并实现目标接口,通过调用原始类的方法来实现目标接口的方法。

04.适配器应用解析

类适配器:现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器,将TF卡中的内容读取出来。

对象适配器:有一个MediaPlayer接口,它可以播放mp3格式的文件。现在,我们想扩展这个功能,使其也可以播放其他格式的文件,比如vlc和mp4。

05.应用场景分析

一般来说,适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。应用这种模式算是“无奈之举”。如果在设计初期,我们就能协调规避接口不兼容的问题,那这种模式就没有应用的机会了。

  1. 封装有缺陷的接口设计。
  2. 设计统一多个类的接口。
  3. 替换依赖的外部系统。
  4. 兼容老版本接口。
  5. 适配不同格式的数据。

08.装饰者模式设计思想

01.装饰者模式基础

给一个类或者对象增加行为:1.继承,子类通过重写父类方法修改行为。2.关联机制,将一个类的对象嵌入另一个对象中用于行为拓展。

装饰者模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

装饰者模式适用于以下场景:

  1. 动态地给一个对象添加额外的功能,而不需要修改其原始类的代码。
  2. 需要扩展一个类的功能,但是使用继承会导致类的数量急剧增加。
  3. 需要在不影响其他对象的情况下,对对象的功能进行动态组合和排列。

02.装饰者模式实现

比如:有一个基本的咖啡对象,可以动态地添加不同的配料(如牛奶和糖)。在不改变对象情况下,对行为进行拓展!

  1. 咖啡A,加牛奶和半糖
  2. 咖啡B,加牛奶和全糖
  3. 咖啡C,加牛奶和多糖
  4. 咖啡D,不加牛奶和半糖

在装饰模式中的角色有:

  1. ● 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  2. ● 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。
  3. ● 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  4. ● 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

03.装饰者实例演示

半透明的装饰者模式是介于装饰者模式和适配器模式之间的。适配器模式的用意是改变所考虑的类的接口,也可以通过改写一个或几个方法,或增加新的方法来增强或改变所考虑的类的功能。大多数的装饰者模式实际上是半透明的装饰者模式,这样的装饰者模式也称做半装饰、半适配器模式。

04.装饰器模式场景

装饰者模式在Java语言中的最著名的应用莫过于Java I/O标准库的设计了。

IO流中装饰者模式结构如下所示:

  1. 抽象构件(Component)角色:由InputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。
  2. 具体构件(ConcreteComponent)角色:由ByteArrayInputStream、FileInputStream、PipedInputStream、StringBufferInputStream等类扮演。它们实现了抽象构件角色所规定的接口。
  3. 抽象装饰(Decorator)角色:由FilterInputStream扮演。它实现了InputStream所规定的接口。
  4. 具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedInputStream、DataInputStream以及两个不常用到的类LineNumberInputStream、PushbackInputStream。

05.装饰器模式分析

09.外观模式设计思想

01.外观模式基础

外观模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,外观模式被引入。

定义是:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。

主要解决的问题

  1. 降低客户端与复杂子系统之间的耦合度。
  2. 简化客户端对复杂系统的操作,隐藏内部实现细节。

02.外观模式实现

假设有一个电脑系统,包含了多个子系统,如音乐功能、视频功能和联网功能。可以打开或者关闭某功能。

实现方式

  1. 创建外观类:定义一个类(外观),作为客户端与子系统之间的中介。提供Facade接口,抽象出通用方法打开和关闭。
  2. 封装子系统操作:外观类将复杂的子系统操作封装成简单的方法。三个子系统类(Subsystem):音乐功能、视频功能和联网功能

比如该案例中:

  1. 针对音乐,视频,联网抽象出通用功能,定义成接口【打开和关闭】。充分体现出面向对象中抽象的设计思想!
  2. 针对音乐,视频,联网各个子系统之间的交互,将他们的逻辑封装到外观类中,充分体现出封装的原则!

03.外观实例演示

有个需求:我们知道在UI开发中,可以绘制很多图像。比如可以绘制圆形,绘制矩形,绘制椭圆形,绘制……来达到绘制显示的效果。

05.外观模式分析

外观模式优点:1.简化接口;2.降低耦合;3.提高灵活性;4.方便维护

外观模式缺点:1.当添加新的子类系统,可能需要修改外观类,或者破坏开闭原则;

使用建议:建议1不要通过外观类给子类系统加入新的行为

10.桥接模式设计思想

01.桥接模式基础

桥接模式的由来是为了解决软件系统中的复杂性和耦合性问题。在大型软件系统中,各个子系统之间可能存在复杂的依赖关系和交互逻辑,这导致了系统的可维护性和可扩展性变得困难。为了简化客户端与子系统之间的交互,桥接模式被引入。

桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。

主要解决的问题:桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联来取代传统的多层继承,将类之间的静态继承关系转变为动态的组合关系,使得系统更加灵活,并易于扩展。

02.桥接模式实现

假设有一个几何形状Shape类,从它能扩展出两个子类:圆形Circle和方形Square。对这样的类层次结构进行扩展以使其包含颜色,所以你打算创建名为红色Red和蓝色Blue的形状子类。

桥接模式实现如下所示:

  1. 创建一个抽象类 Shape,它有一个抽象方法 draw()。
  2. 抽象化角色的子类,创建两个实现了 Shape 接口的具体类:Circle 和 Square。
  3. 创建一个桥接类 Color,它也实现了 Shape 接口,并持有一个 Shape 类型的引用。
  4. 在主函数中测试这个桥接模式。

03.桥接实例演示

如微信和支付宝都可以完成支付操作,而支付操作又可以有扫码支付、密码支付、人脸支付等,那么关于支付操作其实就有两个维度,包括:支付渠道和支付方式。

不使用设计模式来模拟实现不同模式的支付场景。不使用设计模式缺点:维护和扩展都会变得非常复杂,需要修改原来代码,风险较大。

以后若增加支付渠道或修改支付方式,比如增加了京东支付,抖音支付,或者增加一个微信刷掌支付,则成本比较高,不利于后边的扩展和维护。

桥接模式原理的核心是: 首先有要识别出一个类所具有的的两个独立变化维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。

11.组合模式设计思想

01.组合模式基础

组合模式定义 :将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

主要解决的问题 :1.简化树形结构中对象的处理,无论它们是单个对象还是组合对象。2.解耦客户端代码与复杂元素的内部结构,使得客户端可以统一处理所有类型的节点。

02.组合模式实现

组合模式包含如下角色:

  1. 组件(Component): 定义了组合中所有对象的通用接口,可以是抽象类或接口。它声明了用于访问和管理子组件的方法,包括添加、删除、获取子组件等。
  2. 叶子节点(Leaf): 表示组合中的叶子节点对象,叶子节点没有子节点。它实现了组件接口的方法,但通常不包含子组件。
  3. 复合节点(Composite): 表示组合中的复合对象,复合节点可以包含子节点,可以是叶子节点,也可以是其他复合节点。它实现了组件接口的方法,包括管理子组件的方法。
  4. 客户端(Client): 通过组件接口与组合结构进行交互,客户端不需要区分叶子节点和复合节点,可以一致地对待整体和部分。

04.组合实现方式

组合模式分为透明式的组合模式和安全式的组合模式。这两种类型的主要区别在于抽象构件(Component)角色上的差别。

  1. 透明式的组合模式:在透明式的组合模式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。
  2. 安全式的组合模式:在安全式的组合模式中,将管理子构件的方法移到树枝构件中,抽象构件只定义树枝构件和树叶构件所共同的方法。避免了透明式的组合模式的空实现或抛异常问题。

12.享元模式设计思想

01.享元模式基础介绍

享元模式由来,主要是解决对象太多创建的问题:

  1. 享元模式通过共享技术实现相同或相似对象的重用。
  2. 在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。

**享元模式(Flyweight Pattern)**的定义:

运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。

工作中遇到场景:缓存,字符串常量池,线程池,连接池。

贡献者: yangchong211