当前位置: 首页 > news >正文

从0开始学PHP面向对象内容之常用设计模式(策略,观察者)

在这里插入图片描述

PHP设计模式——行为型模式

PHP 设计模式中的行为模式(Behavioral Patterns)主要关注对象之间的通信和交互。行为模式的目的是在不暴露对象之间的具体通信细节的情况下,定义对象的行为和职责。它们常用于解决对象如何协调工作的问题,提高系统的灵活性、可扩展性和可维护性。

1、策略模式(Strategy Pattern)

概述

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以互相替换,该模式使得算法可以独立于使用它的客户端变化。也就是说,测策略模式让一个类的行为可以在运行时被改变,从而实现不同的业务逻辑。

结构

策略模式的结构通常包含以下几个组成部分:
1、Context(环境类)
维护一个指向具体策略类的引用。
向客户端暴露一个公共的接口,用于调用具体的策略行为
2、Strategy(策略接口)
定义一个统一的策略接口,通常是一个抽象类或者接口,所有具体策略类都实现这个接口,包含算法的具体实现。
3、ConcreteStrategy(具体策略类):
实现策略接口中的算法

实例

以一个简单的支付系统为例,假设用户可以选择不同的支付方式(如支付宝、微信支付、信用卡支付等),我们可以使用策略模式来实现。

// 策略接口
public interface PaymentStrategy {void pay(int amount);
}// 具体策略:支付宝支付
public class AlipayStrategy implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("使用支付宝支付 " + amount + " 元");}
}// 具体策略:微信支付
public class WeChatPayStrategy implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("使用微信支付 " + amount + " 元");}
}// 具体策略:信用卡支付
public class CreditCardStrategy implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("使用信用卡支付 " + amount + " 元");}
}// 上下文类
public class PaymentContext {private PaymentStrategy paymentStrategy;// 通过构造器或setter方法注入具体策略public PaymentContext(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}// 执行支付public void executePayment(int amount) {paymentStrategy.pay(amount);}// 设置不同的支付策略public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建不同的支付策略PaymentStrategy alipay = new AlipayStrategy();PaymentStrategy weChatPay = new WeChatPayStrategy();PaymentStrategy creditCard = new CreditCardStrategy();// 创建上下文,选择支付方式PaymentContext context = new PaymentContext(alipay);context.executePayment(100);// 改变支付策略context.setPaymentStrategy(weChatPay);context.executePayment(200);context.setPaymentStrategy(creditCard);context.executePayment(300);}
}

运行结果

使用支付宝支付 100 元
使用微信支付 200 元
使用信用卡支付 300

适用场景

多种算法或行:系统有多种算法或行为可供选择,并且算法都是动态的。
避免条件语句:在系统中有大量的条件语句(if…else…或者switch…case)来选择算法,使用策略模式可以代替这些条件语句,使得代码更加清晰和灵活。
算法经常变化:如果算法经常变化,使用策略模式能够使得新增或修改算法变得更加容易,而不需要修改使用算法的客户端代码

变种与扩展

StatePattern(状态模式):状态模式和策略模式很相似,都是行为型设计模式,都会根据某些条件改变行为。它们的不同点在于,策略模式通常关注算法的选择,而状态模式关注的是对象的状态。
Template MethodPattern(模板方法模式):模板方法模式定义了算法的框架,并将一些步骤延迟到子类中,策略模式则是通过策略接口提供算法的替代方案。

小结

策略模式是为了让客户端能够在运行时选择合适的算法,而不需要修改具体的类,实现了算法的封装和解耦。通过定义统一的策略接口,将不同的算法封装到不同的策略类中,增强了系统的灵活性和可扩展性。

优点

算法封装:策略模式将每个算法封装到独立的策略类中,可以避免使用大量的条件判断,提升代码的可维护性和扩展性
可以动态切换:客户端可以在运行时切换不同的策略,不必在编译时就确定

缺点

增加类的数量:为了实现策略模式,往往需要为每个具体的策略都创建一个类,这可能导致类的数量增加,增加了系统的复杂性
客户端需要知道所有的策略:客户端必须了解所i有的可用的策略,这会导致客户端代码对具体策略的依赖性比较强

2、观察者模式(Observer Pattern)

概述

是一种行为设计模式,定义了对象之间的一种一对多依赖关系。当一个对象的状态发生变化时,所有依赖于它的对象都会自动得到通知并更新。这种模式常用于实现分布式事件处理系统。

结构

观察者模式主要有以下几个组成部分:
Subject(主题/被观察者):
1、主题对象是被观察的对象,它通常是状态变化的源头。
2、主题对象维护一个观察者列表,当状态变化时,会通知所有观察者
Observer(观察者): 1、观察者对象关注主题对象的状态变化,并在状态变化时进行相应的处理
2、观察者接口通常会定义一个update()的方法,当被观察者状态变化时,update()方法会被调用
ConcreteSubject(具体主题/具体被观察者):
1、具体的被观察者,它实现Subject接口,管理观察者列表,并在状态发生变化时,通知所有注册的观察者
ConcreteObserver:(具体观察者):
1、具体的观察者,继承自Observer接口,实现update()方法,处理观察者状态变化时的响应

示例

<?php<?php// 观察者接口
interface Observer {public function update($news);
}// 主题接口
interface Subject {public function registerObserver(Observer $observer);public function removeObserver(Observer $observer);public function notifyObservers();
}// 具体的主题类
class NewsAgency implements Subject {private $observers = [];private $news;// 注册观察者public function registerObserver(Observer $observer) {$this->observers[] = $observer;}// 移除观察者public function removeObserver(Observer $observer) {$index = array_search($observer, $this->observers);if ($index !== false) {unset($this->observers[$index]);}}// 通知所有观察者public function notifyObservers() {foreach ($this->observers as $observer) {$observer->update($this->news);}}// 设置新闻并通知观察者public function setNews($news) {$this->news = $news;$this->notifyObservers(); // 发布新闻时通知所有观察者}
}// 具体的观察者类
class User implements Observer {private $name;public function __construct($name) {$this->name = $name;}public function update($news) {echo $this->name . " 收到新闻更新: " . $news . PHP_EOL;}
}// 客户端代码
$newsAgency = new NewsAgency();// 创建具体的观察者(用户)
$user1 = new User("Alice");
$user2 = new User("Bob");
$user3 = new User("Charlie");// 注册观察者
$newsAgency->registerObserver($user1);
$newsAgency->registerObserver($user2);
$newsAgency->registerObserver($user3);// 发布新闻
$newsAgency->setNews("今天的新闻头条:PHP 设计模式");// 移除观察者
$newsAgency->removeObserver($user2);// 发布新新闻
$newsAgency->setNews("今天的新闻头条:观察者模式在PHP中的实现");?>

运行结果

Alice 收到新闻更新: 今天的新闻头条:PHP 设计模式
Bob 收到新闻更新: 今天的新闻头条:PHP 设计模式
Charlie 收到新闻更新: 今天的新闻头条:PHP 设计模式
Alice 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现
Charlie 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现

适用场景

观察者模式适用于以下情况:
事件驱动系统:例如,点击事件、输入框变化事件等。
消息推送系统:如新闻推送、天气更新推送等。
实时数据监控系统:比如股票行情、体育比赛数据的实时更新。
GUI框架:如按钮点击、窗口变化等事件处理。

变种与扩展

推模型与拉模型
推模型:主题对象将更新的内容主动推送给观察者。例如,主题直接将新闻内容传递给观察者。
拉模型:观察者通过主题对象拉取更新内容。例如,观察者请求最新的新闻内容,而不是由主题主动推送。 发布-订阅模式(Pub-Sub)

发布-订阅模式是一种广泛使用的观察者模式变种,常常结合消息队列或事件总线。它不仅可以将事件通知从发布者传递给订阅者,还支持消息过滤、延迟通知等功能。

小结

观察者模式是一种非常实用的设计模式,适用于需要多个对象响应某个对象状态变化的场景。通过解耦对象之间的关系,它使得系统更加灵活和可扩展。虽然在某些复杂系统中可能会引入性能或管理上的挑战,但其简单和直观的实现方式使得它在很多场合得到了广泛应用。在 PHP 中实现观察者模式相对简单,能够帮助开发者构建高效、灵活的事件驱动系统。

优点

解耦:观察者模式让主题和观察者之间不直接依赖,主题不知道观察者的具体类,观察者也不知道主题的具体内容,二者只通过接口进行交互。这样,系统更加灵活,可扩展性强。
动态更新:观察者模式使得系统能够在运行时动态添加或移除观察者,无需修改主题类或已有的观察者类。
多播通信:一个主题可以同时通知多个观察者,适合于广播式的事件处理(如推送通知、实时消息更新等)。

缺点

可能导致内存泄漏:如果观察者没有及时取消订阅,可能会导致主题无法被垃圾回收,从而造成内存泄漏。
依赖链复杂:在某些复杂系统中,观察者之间可能会互相依赖,从而形成复杂的依赖关系,增加系统的复杂度。
通知开销:如果观察者数量很多,每次通知可能需要遍历所有观察者,影响性能。

相关文章:

从0开始学PHP面向对象内容之常用设计模式(策略,观察者)

PHP设计模式——行为型模式 PHP 设计模式中的行为模式&#xff08;Behavioral Patterns&#xff09;主要关注对象之间的通信和交互。行为模式的目的是在不暴露对象之间的具体通信细节的情况下&#xff0c;定义对象的行为和职责。它们常用于解决对象如何协调工作的问题&#xff…...

前端 如何用 div 标签实现 步骤审批

在前端实现一个步骤审批流程&#xff0c;通常是通过 div 标签和 CSS 来构建一个可视化的流程图&#xff0c;结合 JavaScript 控制审批的状态变化。你可以使用 div 标签创建每一个步骤节点&#xff0c;通过不同的样式&#xff08;如颜色、边框等&#xff09;表示审批的不同状态&…...

【大数据技术基础 | 实验十四】Kafka实验:订阅推送示例

文章目录 一、实验目的二、实验要求三、实验原理&#xff08;一&#xff09;Kafka简介&#xff08;二&#xff09;Kafka使用场景 四、实验环境五、实验内容和步骤&#xff08;一&#xff09;配置各服务器之间的免密登录&#xff08;二&#xff09;安装ZooKeeper集群&#xff08…...

SpringAi整合大模型(进阶版)

进阶版是在基础的对话版之上进行新增功能。 如果还没弄出基础版的&#xff0c;请参考 https://blog.csdn.net/weixin_54925172/article/details/144143523?sharetypeblogdetail&sharerId144143523&sharereferPC&sharesourceweixin_54925172&spm1011.2480.30…...

为什么爱用低秩矩阵

目录 为什么爱用低秩矩阵 一、定义与性质 二、区别与例子 为什么爱用低秩矩阵 我们更多地提及低秩分解而非满秩分解,主要是因为低秩分解在数据压缩、噪声去除、模型简化和特征提取等方面具有显著的优势。而满秩分解虽然能够保持数据的完整性,但在实际应用中的场景较为有限…...

React 自定义钩子:useOnlineStatus

我们今天的重点是 “useOnlineStatus” 钩子&#xff0c;这是 React 自定义钩子集合中众多精心制作的钩子之一。 Github 的&#xff1a;https://github.com/sergeyleschev/react-custom-hooks import { useState } from "react" import useEventListener from &quo…...

uniapp 小程序 监听全局路由跳转 获取路由参数

uniapp 小程序 监听全局路由跳转 获取路由参数 app.vue中 api文档 onLaunch: function(options) {let that this;let event [navigateTo, redirectTo, switchTab, navigateBack];event.forEach(item > {uni.addInterceptor(item, { //监听跳转//监听跳转success(e) {tha…...

12.02 深度学习-卷积

# 卷积 是用于图像处理 能够保存图像的一些特征 卷积层 如果用全连接神经网络处理图像 计算价格太大了 图像也被转为线性的对象导致失去了图像的空间特征 只有在卷积神经网络cnn的最后一层使用全连接神经网络 # 图像处理的三大任务 # 目标检测 对图像中的目标进行框出来 # 图…...

MySQL 主从同步一致性详解

MySQL主从同步是一种数据复制技术&#xff0c;它允许数据从一个数据库服务器&#xff08;主服务器&#xff09;自动同步到一个或多个数据库服务器&#xff08;从服务器&#xff09;。这种技术主要用于实现读写分离、提升数据库性能、容灾恢复以及数据冗余备份等目的。下面将详细…...

Spring源码导入idea时gradle构建慢问题

当我们将spring源码导入到idea进行构建的时候&#xff0c;spring采用的是gradle进行构建&#xff0c;默认下注在依赖是从https://repo.maven.apache.org会特别慢&#xff0c;需要改为国内的镜像地址会加快速度。 将项目中build.gradle配置进行调整&#xff1a; repositories …...

Dockerfile 安装echarts插件给java提供服务

java调用echarts插件&#xff0c;生成图片保存到磁盘然后插入到pptx中报表。 Dockerfile文件内容&#xff1a; #基础镜像&#xff0c;如果本地仓库没有&#xff0c;会从远程仓库拉取 openjdk:8 FROM docker.io/centos:centos7 #暴露端口 EXPOSE 9311 # 避免centos 日志输出 …...

Springboot小知识(1):启动类与配置

一、启动类&#xff08;引导类&#xff09; 在通常情况下&#xff0c;你创建的Spring应用项目都会为你自动生成一个启动类&#xff0c;它是这个应用的起点。 在Spring Boot中&#xff0c;引导类&#xff08;也称为启动类&#xff0c;通常是main方法所在的类&#xff09;是整个…...

[CISCN 2019华东南]Web11

[CISCN 2019华东南]Web11 给了两个链接但是都无法访问 这里我们直接抓包试一下 我们插入X-Forwarded-For:127.0.0.1 发现可以修改了右上角的IP地址&#xff0c;从而可以进行注入 {$smarty.version} 查看版本号 if标签执行PHP命令 {if phpinfo()}{/if} 查看协议 {if system(…...

Cypress内存溢出奔溃问题汇总

内存溢出报错信息 <--- Last few GCs ---> [196:0xe58001bc000] 683925 ms: Scavenge 1870.7 (1969.9) -> 1865.6 (1969.9) MB, 6.07 / 0.00 ms (average mu 0.359, current mu 0.444) task; [196:0xe58001bc000] 683999 ms: Scavenge 1872.4 (1969.9) -> 1867.1…...

树莓派4B--OpenCV安装踩坑

报错&#xff1a; Source directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329 Working directory: /tmp/pip-install-pv7l9r25/opencv-python_08fdf5a130a5429f89b0e0eaab39a329/_skbuild/linux-armv7l-3.7/cmake-build Please check the i…...

电子电气架构 --- 面向服务的汽车诊断架构

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧,都是来源于自己的想象,只有你真的去做了,才会发现有多快乐。…...

Pytest --capture 参数详解:如何控制测试执行过程中的输出行为

--capture 选项用于控制测试用例执行过程中标准输出&#xff08;stdout&#xff09;和标准错误输出&#xff08;stderr&#xff09;的捕获行为。 --capture 的选项值&#xff1a; fd&#xff08;默认&#xff09; 捕获文件描述符级别的输出&#xff08;stdout 和 stderr&#x…...

IS-IS的原理

IS-IS的基本概念&#xff1a; 概述&#xff1a; IS-IS&#xff0c;中间系统到中间系统&#xff0c;是ISO国际标准化组织为它的无连接网络协议设计的一种动态路由协议 IS-IS支持CLNP网络和IP网络&#xff0c;采用数据链路层封装&#xff0c;区别于ospf只支持IP网络&#xff0…...

C++(4个类型转换)

1. C语言中的类型转换 1. 隐式 类型转换&#xff1a; 具有相近的类型才能进行互相转换&#xff0c;如&#xff1a;int,char,double都表示数值。 2. 强制类型转换&#xff1a;能隐式类型转换就能强制类型转换&#xff0c;隐式类型之间的转换类型强相关&#xff0c;强制类型转换…...

Ubuntu20.04安装NVIDIA显卡驱动

Ubuntu20.04安装NVIDIA显卡驱动 参考资料&#xff1a;https://blog.csdn.net/weixin_39244242/article/details/136282614?fromshareblogdetail&sharetypeblogdetail&sharerId136282614&sharereferPC&sharesourceqq_37397652&sharefromfrom_link 成功配置…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

高频面试之3Zookeeper

高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个&#xff1f;3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制&#xff08;过半机制&#xff0…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

NPOI操作EXCEL文件 ——CAD C# 二次开发

缺点:dll.版本容易加载错误。CAD加载插件时&#xff0c;没有加载所有类库。插件运行过程中用到某个类库&#xff0c;会从CAD的安装目录找&#xff0c;找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库&#xff0c;就用插件程序加载进…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

高考志愿填报管理系统---开发介绍

高考志愿填报管理系统是一款专为教育机构、学校和教师设计的学生信息管理和志愿填报辅助平台。系统基于Django框架开发&#xff0c;采用现代化的Web技术&#xff0c;为教育工作者提供高效、安全、便捷的学生管理解决方案。 ## &#x1f4cb; 系统概述 ### &#x1f3af; 系统定…...