从0开始学PHP面向对象内容之常用设计模式(适配器,桥接,装饰器)
二,结构型设计模式
上两期咱们讲了创建型设计模式,都有 单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式五个设计模式。
这期咱们讲结构型设计模式
1、适配器模式(Adapter)
什么是适配器模式?
适配器模式是一种结构型设计模式,用于将一个类的接口转换为另一个接口,以满足客户端的使用需求,它允许本来由于接口不兼容而不能一起工作的类可以协同工作。
适配器模式的核心概念
1、目标接口(Target):客户端需要的接口。
2、适配者(Adaptee):已有的类,其他接口与目标接口普不兼容
3、适配器(Adapter):将适配者接口转换为目标接口
适配器模式的类型
对象适配器:通过组合(包含适配者对象)实现适配
类适配器:通过继承适配者实现适配(php不支持多继承,因此 类的适配器较少使用,其他语言可能会多一些)
适配器模式的结构
Client端:客户端,使用Target接口
Target:目标接口
Adaptee:适配者类,具有不兼容接的接口
Adapter:适配器类,实现Target接口,并包含Adaptee的引用
使用场景
1、当你希望使用现有的类,但接口不符合需求
2、当你想复用现有的类,而无需修改它
3、需要兼容多个版本或不同的接口系统
实现
<?php
// 目标接口 (Target)
interface Target {public function request();
}// 适配者 (Adaptee)
class Adaptee {public function specificRequest() {return "Adaptee's specific behavior";}
}// 适配器 (Adapter)
class Adapter implements Target {private $adaptee;public function __construct(Adaptee $adaptee) {$this->adaptee = $adaptee;}public function request() {// 将适配者的方法适配为目标方法return $this->adaptee->specificRequest();}
}// 客户端代码 (Client)
function clientCode(Target $target) {echo $target->request();
}// 使用适配器模式
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
clientCode($adapter);
输出
Adaptee’s specific behavior
应用案例
1、数据库适配器:PHP 中常用的 PDO 就是一个数据库适配器,统一了对多种数据库的操作接口。
2、日志适配器:适配不同的日志系统(如 Monolog 和其他日志库)。
3、跨平台接口:将平台 A 的 API 转换为平台 B 的 API 形式。
小结
优点
1、适配器隔离了客户端与具体类的实现,遵循开闭原则
2、提高代码的复用性,现有的类可以被重复利用。
3、增强代码的灵活性,使得类之间协作更方便
缺点
增加了系统的复杂性
对于复杂的适配逻辑,可能导致适配器代码较为繁琐
2、桥接模式(Bridge)
什么是桥接模式
桥接模式是一种结构型设计模式,它通过将抽象部分与实现部分分离,使它们可以独立变化。它的核心思想是使用组合而非继承来解决类的多维度变化问题。
桥接模式的概念
1、抽象部分(Abstraction):定义高层的控制逻辑,依赖于实现部分(Implementor)。
2、实现部分(Implementor):定义具体的实现接口,不与抽象部分直接耦合
3、细化抽象:抽象部分的具体子类
4、具体实现:实现部分的具体实现
通过将这两部分分离,可以独立扩展两者,而不会互相影响
桥接模式的结构
1、Abstraction:抽象类,维护对Implementor的引用。
2、Implementor:实现接口,为具体实现提供方法。
3、RefinedAbstraction:抽象类的扩展,实现具体的功能。
4、ConcreteImplementor:实现接口的具体类
使用场景
1、类有多个纬度的变化,且每个纬度都需要独立扩展
2、希望避免使用继承来扩展类时。
3、需要再运行时切换
实现
以下是一个简单的例子:实现多种形状(Shape),支持不同的颜色(Color)
<?php
// 实现接口 (Implementor)
interface Color {public function applyColor();
}// 具体实现类 (ConcreteImplementor)
class Red implements Color {public function applyColor() {return "Red";}
}class Blue implements Color {public function applyColor() {return "Blue";}
}// 抽象类 (Abstraction)
abstract class Shape {protected $color;public function __construct(Color $color) {$this->color = $color;}abstract public function draw();
}// 细化抽象类 (RefinedAbstraction)
class Circle extends Shape {public function draw() {return "Circle colored in " . $this->color->applyColor();}
}class Square extends Shape {public function draw() {return "Square colored in " . $this->color->applyColor();}
}// 客户端代码 (Client)
$redColor = new Red();
$blueColor = new Blue();$redCircle = new Circle($redColor);
$blueSquare = new Square($blueColor);echo $redCircle->draw(); // 输出: Circle colored in Red
echo $blueSquare->draw(); // 输出: Square colored in Blue
桥接模式的实现过程
1、定义实现接口:实现部分的接口,为具体实现提供规范
2、实现具体类:具体实现的接口,具有独立的功能
3、定义抽象类:抽象部分的基类,包含实现接口的引用
4、实现细化类:抽象类的具体子类,实现客户端需要的具体功能
5、组合抽象与实现:通过组合的方式,将实现部分传递给抽象部分
实际应用
1、图形库:将图形(形状)和渲染方式分离,例如形状可以时圆形,矩形而渲染方式可以时适量渲染,栅格渲染
2、设备和控制器:控制器(抽象部分)独立于设备(实现部分),如遥控器与电视机
3、日志系统:日志框架可以有多种日志目标(文件,数据库),日志格式和目标分离
小结
优点:
1、分离抽象与实现:两者可以独立扩展符合单一职责原则
2、动态切换实现;运行时可以轻松替换实现部分
3、减少子类数量:避免以为多维度扩展导致的类爆炸
缺点:
增加复杂性:抽象与实现的分离增加了系统的复杂性
可能导致过度设计:如果维度不多或变化不频繁,使用桥接模式可能显得多余
3、 装饰器模式(Decorator)
什么是装饰器模式
装饰器模式是一种结构型设计模式,它允许动态地向对象添加新功能,而不需要修改对象地定义或使用继承,装饰器模式使用一种对象包装另一种对象地方式,为被包装对象提供额外地功能
装饰器模式地核心概念
1、组件(Component):定义对象接口
2、具体组件(Concrete Component):实现组件接口地类,是被装饰地对象
2、装饰器(Decorator):实现组件接口,同时包含一个指向组件对象地引用,用户扩展组件功能
4、具体装饰器(Concrete Decorator):实现装饰器功能,向被装饰对象添加额外地功能
使用场景
1、不希望修改已有代码但需要增加功能时
2、希望在运行时动态扩展对象功能时
3、需要组合多个装饰功能,并保持功能独立
实现
以下是一个简单的例子:装饰一段文本,支持多种功能如加粗、斜体等。
<?php
// 组件接口 (Component)
interface Text {public function render(): string;
}// 具体组件 (ConcreteComponent)
class PlainText implements Text {private $text;public function __construct(string $text) {$this->text = $text;}public function render(): string {return $this->text;}
}// 装饰器 (Decorator)
abstract class TextDecorator implements Text {protected $text;public function __construct(Text $text) {$this->text = $text;}
}// 具体装饰器 (ConcreteDecorator)
class BoldText extends TextDecorator {public function render(): string {return "<b>" . $this->text->render() . "</b>";}
}class ItalicText extends TextDecorator {public function render(): string {return "<i>" . $this->text->render() . "</i>";}
}// 客户端代码 (Client)
$plainText = new PlainText("Hello, World!");// 添加加粗功能
$boldText = new BoldText($plainText);
echo $boldText->render(); // 输出: <b>Hello, World!</b>// 添加斜体功能
$italicText = new ItalicText($boldText);
echo $italicText->render(); // 输出: <i><b>Hello, World!</b></i>
实际应用
1、**日志系统:**装饰日志功能:将日志存储到文件、发送到远程服务器或格式化为 JSON。
2、用户界面(UI)组件:如 Qt 和
Swing,按钮可以动态添加边框、阴影等样式。
3、数据流处理:PHP 中的 Stream,通过包装实现加密、压缩等功能。
4、动态权限检查:为服务接口动态添加权限验证、日志记录等功能。
小结
优点
1、开闭原则:无需修改原始对象即可扩展功能
2、高扩展性:可以创建任意数量的装饰器类,并以灵活的方式组合
3、运动时动态性:可以动态的为对象添加或移除功能
缺点
1、增加复杂性:多层装饰器会导致系统复杂度上升,调试变得困难
2、依赖组件接口:装饰器与被装饰的对象都必须实现相同接口
总结
桥接模式,适配器模式,装饰器模式对比
相关文章:

从0开始学PHP面向对象内容之常用设计模式(适配器,桥接,装饰器)
二,结构型设计模式 上两期咱们讲了创建型设计模式,都有 单例模式,工厂模式,抽象工厂模式,建造者模式,原型模式五个设计模式。 这期咱们讲结构型设计模式 1、适配器模式(Adapter) …...

玩转数字与运算:用C语言实现24点游戏的扑克牌魅力
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

前端入门之VUE--基础与核心
前言 VUE是前端用的最多的框架;这篇文章是本人大一上学习前端的笔记;欢迎点赞 收藏 关注,本人将会持续更新。 Vue学习笔记 用于构建用户界面的渐进式框架 构建用户界面:基于数据动态渲染页面渐进式:循序渐近的学…...

logback 初探学习
logback 三大模块 记录器(Logger)、追加器(Appender)和布局(Layout) 配置文件外层最基本的标签如图示 xml中定义的就是这个三个东西下面进入学习 包引入参考springboot 官方文档 Logging :: Spring Boo…...

在Elasticsearch中,是怎么根据一个词找到对应的倒排索引的?
大家好,我是锋哥。今天分享关于【在Elasticsearch中,是怎么根据一个词找到对应的倒排索引的?】面试题。希望对大家有帮助; 在Elasticsearch中,是怎么根据一个词找到对应的倒排索引的? 在 Elasticsearch 中…...

1992-2021年 各省市县经过矫正的夜间灯光数据(GNLD、VIIRS)区域汇总:省份、城市、区县面板数据
1992-2021年 各省市县经过矫正的夜间灯光数据(GNLD、VIIRS)区域汇总:省份、城市、区县面板数据 .r.rar https://download.csdn.net/download/2401_84585615/90001905 从1992年至2021年,中国各省份、城市及区县的夜间灯光数据经过…...

linux实战-黑链——玄机靶场
黑链的特征: 隐藏链接:黑链通常隐藏在网站页面中,使用CSS、JavaScript或其他手段使其对普通用户不可见,但仍然能被搜索引擎爬虫检测到。恶意内容:这些链接指向的内容可能包含恶意软件、钓鱼页面或其他不良内容&#x…...

鸿蒙NEXT开发案例:字数统计
【引言】 本文将通过一个具体的案例——“字数统计”组件,来探讨如何在鸿蒙NEXT框架下实现这一功能。此组件不仅能够统计用户输入文本中的汉字、中文标点、数字、以及英文字符的数量,还具有良好的用户界面设计,使用户能够直观地了解输入文本…...

uniapp vue2项目迁移vue3项目
uniapp vue2项目迁移vue3项目,必须适配的部分 一、main.js 创建应用实例 // 之前 - Vue 2 import Vue from vue import App from ./App Vue.config.productionTip false // vue3 不再需要 App.mpType app // vue3 不再需要 const app new Vue({ ...App }) …...

16.C++STL 3(string类的模拟,深浅拷贝问题)
⭐本篇重点:string类的模拟,自己实现一个简单的string类 ⭐本篇代码:c学习/05.string类的学习 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) 目录 一. 经典string类的模拟 1.1 深浅拷贝问题 1.2 使用深拷贝完成经典string类的…...
神经网络10-Temporal Fusion Transformer (TFT)
Temporal Fusion Transformer (TFT) 是一种专为时序数据建模而设计的深度学习模型,它结合了Transformer架构和其他技术,旨在有效地处理和预测时序数据中的复杂模式。TFT 于 2020 年由 Google Research 提出,旨在解决传统模型在时序预测中的一…...

“iOS profile文件与私钥证书文件不匹配”总结打ipa包出现的问题
目录 文件和证书未加载或特殊字符问题 证书过期或Profile文件错误 确认开发者证书和私钥是否匹配 创建证书选择错误问题 申请苹果 AppId时勾选服务不全问题 总结 在上线ios平台的时候,在Hbuilder中打包遇见了问题,生成ipa文件时候,一…...

《图像梯度与常见算子全解析:原理、用法及效果展示》
简介:本文深入探讨图像梯度相关知识,详细介绍图像梯度是像素灰度值在不同方向的变化速度,并以 “pig.JPG” 图像为例,通过代码展示如何选取图像部分区域并分析其像素值以论证图像梯度与边缘信息的关联。接着全面阐述了 Sobel 算子,…...

【c++篇】:探索c++中的std::string类--掌握字符串处理的精髓
✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨ ✨ 个人主页:余辉zmh–CSDN博客 ✨文章所属专栏:c篇–CSDN博客 文章目录 前言一.std::string对象的创建二.std::string对象的访问三.std::str…...

LlamaIndex ollama 搭建本地RAG应用,建立本地知识库
目录 简介安装前的准备下载ollama创建llamaindex conda环境,为后面编码作准备 环境变量迁移ollama到其他盘运行ollama方式一方式二禁止ollama开机自启动运行第一个模型 Chatbox聊天下载Chatbox配置ollama地址和模型验证 建立自身特定知识数据搭配大语言模型创建项目…...

draggable的el-dialog实现对话框标题可以选择
请看图 这个对话框使用了el-dialog并且draggable属性设置成了true,所以标题栏这里就可以拖动,现在用户想选中标题栏的文本进而复制。我看到这个需求头都大了。 我能想到的方案有三个:1. 取消draggable为true 2. 标题文案后面加一个复制按钮 …...
2024年Android面试总结
2024年Android面试总结 1.动画类型有哪些?插值器原理? 2.StringBuffer和StringBuilder区别? 3.jvm内存模型? 4.线程池7大核心参数及原理? 5.Android多进程通信方式有哪些?各自的优缺点? 6…...

树莓派3:64位系统串口(UART)使用问题的解决方法
前言 当我们要使用串口进行zigbee的短距离通信时,发现无法使用串口. 原因 树莓派3bCPU内部有两个串口,一个硬件串口(就是我们平时使用的UART),还有一个迷你串口(mini-uart),在老版本的树莓派中把硬件串口分配在GPIO上,可以单独使用.但是在新的树莓派中官方把硬件串口给了蓝牙…...

SemiDrive E3 硬件设计系列---唤醒电路设计
一、前言 E3 系列芯片是芯驰半导体高功能安全的车规级 MCU,对于 MCU 的硬件设计部分,本系列将会分模块进行讲解,旨在介绍 E3 系列芯片在硬件设计方面的注意事项与经验,本文主要讲解 E3 硬件设计中唤醒电路部分的设计。 二、RTC 模…...
淘宝接口高并发采集核心要点解读,开启电商数据智能应用新纪元
一、引言 在电商蓬勃发展的今天,淘宝作为全球知名的电商巨头,其平台上的数据犹如一座蕴藏无限价值的宝藏。准确且高效地采集淘宝接口数据,并通过高并发技术实现大规模数据获取,对于电商企业的精准营销、市场趋势分析、竞品监测以及…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...