thnkphp 项目 设计模式运用(项目设计模型)
itomcoil 2025-06-15 16:58 9 浏览
## 一、设计模式在ThinkPHP项目中的运用
### (一)单例模式
1. **应用场景**
- 在ThinkPHP项目中,数据库连接是一个典型的单例模式应用场景。因为对于一个应用来说,通常只需要一个数据库连接实例。例如,当多个模块或控制器需要访问数据库时,如果每次都创建新的数据库连接,会浪费资源并且可能造成数据库连接过多的问题。
- 例如,ThinkPHP框架本身在处理数据库连接时,就可能使用单例模式。通过在框架的数据库类中实现单例模式,确保全局只有一个数据库连接实例。像在`Db`类中(以ThinkPHP 5.x为例),可以通过以下方式实现单例:
```php
class Db
{
private static $_instance = null;
private function __construct()
{
// 构造函数私有化,防止外部实例化
}
public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self();
}
return self::$_instance;
}
// 其他数据库操作方法
}
```
- 这样,当多个地方调用`Db::getInstance()`时,都会获取到同一个数据库连接实例,避免了重复连接数据库。
2. **优势**
- 节省系统资源,因为单例模式确保了全局只有一个实例,减少了对象的创建和销毁开销。
- 提供全局访问点,方便在不同模块之间共享同一个实例。
### (二)工厂模式
1. **应用场景**
- 在ThinkPHP项目中,工厂模式可以用于创建模型对象。例如,在一个电商系统中,有多种类型的订单模型,如普通订单模型、团购订单模型和预售订单模型等。通过工厂模式可以根据不同的订单类型来创建对应的模型对象。
- 可以创建一个订单模型工厂类`OrderModelFactory`,代码示例如下:
```php
class OrderModelFactory
{
public static function createOrderModel($type)
{
switch ($type) {
case 'normal':
return new NormalOrderModel();
case 'group':
return new GroupOrderModel();
case 'pre_sale':
return new PreSaleOrderModel();
default:
throw new Exception("Invalid order type");
}
}
}
```
- 在控制器中,就可以通过`
OrderModelFactory::createOrderModel($type)`来获取对应的订单模型对象,而不需要在控制器中直接实例化模型类,这样提高了代码的可维护性和扩展性。
2. **优势**
- 将对象的创建和使用分离,降低了客户端代码与具体类之间的耦合度。当需要添加新的订单类型模型时,只需要在工厂类中添加对应的创建逻辑,而不需要修改客户端代码。
- 提供了一种统一的接口来创建对象,方便管理和扩展对象的创建过程。
### (三)策略模式
1. **应用场景**
- 在ThinkPHP项目中,策略模式可以用于处理不同的支付方式。例如,一个网站支持多种支付方式,如支付宝、微信支付和银行卡支付等。每种支付方式都有自己的支付逻辑,可以通过策略模式来实现。
- 可以定义一个支付策略接口`PaymentStrategy`,然后为每种支付方式实现这个接口。例如:
```php
interface PaymentStrategy
{
public function pay($amount);
}
class AlipayStrategy implements PaymentStrategy
{
public function pay($amount)
{
// 实现支付宝支付逻辑
}
}
class WechatPayStrategy implements PaymentStrategy
{
public function pay($amount)
{
// 实现微信支付逻辑
}
}
```
- 然后在支付服务类中,根据用户选择的支付方式动态地选择对应的支付策略。例如:
```php
class PaymentService
{
private $paymentStrategy;
public function setPaymentStrategy(PaymentStrategy $strategy)
{
$this->paymentStrategy = $strategy;
}
public function pay($amount)
{
return $this->paymentStrategy->pay($amount);
}
}
```
- 在控制器中,根据用户的选择设置支付策略,如:
```php
$paymentService = new PaymentService();
if ($paymentType == 'alipay') {
$paymentService->setPaymentStrategy(new AlipayStrategy());
} elseif ($paymentType == 'wechat') {
$paymentService->setPaymentStrategy(new WechatPayStrategy());
}
$paymentService->pay($amount);
```
2. **优势**
- 策略模式使得算法的变化独立于使用算法的客户。当需要添加新的支付方式时,只需要添加一个新的支付策略类,而不需要修改支付服务类的代码。
- 提高了代码的可扩展性和可维护性,使得支付逻辑的变更和扩展更加灵活。
### (四)观察者模式
1. **应用场景**
- 在ThinkPHP项目中,观察者模式可以用于实现事件驱动机制。例如,在用户注册时,可能需要触发一系列的操作,如发送欢迎邮件、记录日志、发送短信通知等。这些操作可以作为观察者来响应用户注册这个事件。
- 可以定义一个事件类和观察者接口。例如:
```php
class Event
{
private $observers = [];
public function attach($observer)
{
$this->observers[] = $observer;
}
public function notify()
{
foreach ($this->observers as $observer) {
$observer->update($this);
}
}
}
interface Observer
{
public function update($event);
}
```
- 然后实现具体的观察者,如发送邮件观察者`SendEmailObserver`和记录日志观察者`LogObserver`:
```php
class SendEmailObserver implements Observer
{
public function update($event)
{
// 发送欢迎邮件逻辑
}
}
class LogObserver implements Observer
{
public function update($event)
{
// 记录日志逻辑
}
}
```
- 在用户注册的逻辑中,创建事件对象并注册观察者:
```php
$registerEvent = new Event();
$registerEvent->attach(new SendEmailObserver());
$registerEvent->attach(new LogObserver());
// 用户注册成功后触发事件
$registerEvent->notify();
```
2. **优势**
- 观察者模式使得对象之间可以实现松耦合。事件的发起者(用户注册逻辑)不需要知道具体的观察者(发送邮件、记录日志等操作)的实现细节,只要定义好事件和观察者接口即可。
- 提高了代码的灵活性和可扩展性,方便添加新的观察者来响应事件,而不需要修改事件发起者的代码。
相关推荐
- Java 如何从一个 List 中随机获得元素
-
概述从一个List中随机获得一个元素是有关List的一个基本操作,但是这个操作又没有非常明显的实现。本页面主要向你展示如何有效的从List中获得一个随机的元素和可以使用的一些方法。选择一个...
- 想月薪过万吗?计算机安卓开发之"集合"
-
集合的总结:/***Collection*List(存取有序,有索引,可以重复)*ArrayList*底层是数组实现的,线程不安全,查找和修改快,增和删比较慢*LinkedList*底层是...
- China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report
-
ImagegeneratedbyAITMTPOST--ChinaisclosinginontheU.S.intheAIindustry-academia-research...
- 大促系统优化之应用启动速度优化实践
-
作者:京东零售宋维飞一、前言本文记录了在大促前针对SpringBoot应用启动速度过慢而采取的优化方案,主要介绍了如何定位启动速度慢的阻塞点,以及如何解决这些问题。希望可以帮助大家了解如何定位该类问...
- MyEMS开源能源管理系统核心代码解读004
-
本期解读:计量表能耗数据规范化算法:myems/myems-normalization/meter.py代码见底部这段代码是一个用于计算和存储能源计量数据(如电表读数)的小时值的Python脚本。它主...
- Java接口与抽象类:核心区别、使用场景与最佳实践
-
Java接口与抽象类:核心区别、使用场景与最佳实践一、核心特性对比1.语法定义接口:interface关键字定义,支持extends多继承接口javapublicinterfaceDrawabl...
- 超好看 vue2.x 音频播放器组件Vue-APlayer
-
上篇文章给大家分享了视频播放器组件vue-aliplayer,这次给大家推荐一款音频插件VueAplayer。vue-aplayer一个好看又好用的轻量级vue.js音乐播放器组件。清爽漂亮的U...
- Linq 下的扩展方法太少了,MoreLinq 来啦
-
一:背景1.讲故事前几天看同事在用linq给内存中的两个model做左连接,用过的朋友都知道,你一定少不了一个叫做DefaultIfEmpty函数,这玩意吧,本来很流畅的from......
- MapReduce过程详解及其性能优化(详细)
-
从JVM的角度看Map和ReduceMap阶段包括:第一读数据:从HDFS读取数据1、问题:读取数据产生多少个Mapper??Mapper数据过大的话,会产生大量的小文件,由于Mapper是基于虚拟...
- 手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)
-
来源:Python爬虫与数据挖掘作者:霖hero前言关于Scrapy理论的知识,可以参考我的上一篇文章,这里不再赘述,直接上干货。实战演练爬取分析首先我们进入北京新发地价格行情网页并打开开发者工具,如...
- 屏蔽疯狂蜘蛛,防止CPU占用100%(mumu模拟器和雷电模拟器哪个更占用cpu)
-
站点总是某个时间段莫名的cpu100%,资源占用也不高,这就有必要怀疑爬虫问题。1.使用"robots.txt"规范在网站根目录新建空白文件,命名为"robots.txt...
- Web黑客近年神作Gospider:一款基于Go语言开发的Web爬虫,要收藏
-
小白看黑客技术文章,一定要点首小歌放松心情哈,我最爱盆栽!开始装逼!Gospider是一款运行速度非常快的Web爬虫程序,对于爱好白帽黑客的小白来说,可谓是佳作!Gospider采用厉害的Go语言开发...
- 用宝塔面板免费防火墙屏蔽织梦扫描网站
-
今天教大家在免费的基础上屏蔽织梦扫描,首先您要安装宝塔面板,然后再安装免费的防火墙插件,我用的是Nginx免费防火墙,然后打开这个插件。设置GET-URL过滤设置一条简单的宝塔面板的正则规则就可以屏蔽...
- 蜘蛛人再捞4千万美元 连续三周蝉联北美票房冠军
-
7月15日讯老马追踪票房数据的北美院线联盟今天表示,“蜘蛛人:离家日”(Spider-Man:FarFromHome)击退两部新片的挑战,连续第2周勇夺北美票房冠军,海捞4530万美元。法新...
- 夏天到了,需要提防扁虱,真是又小又恐怖的动物
-
夏天马上要到了,你知道吗,扁虱是这个夏天最危险的动物之一,很少有动物能比它还凶猛。Whenitcomestosummer'slittledangers,fewarenastiert...
- 一周热门
- 最近发表
-
- Java 如何从一个 List 中随机获得元素
- 想月薪过万吗?计算机安卓开发之"集合"
- China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report
- 大促系统优化之应用启动速度优化实践
- MyEMS开源能源管理系统核心代码解读004
- Java接口与抽象类:核心区别、使用场景与最佳实践
- 超好看 vue2.x 音频播放器组件Vue-APlayer
- Linq 下的扩展方法太少了,MoreLinq 来啦
- MapReduce过程详解及其性能优化(详细)
- 手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)
- 标签列表
-
- ps图案在哪里 (33)
- super().__init__ (33)
- python 获取日期 (34)
- 0xa (36)
- super().__init__()详解 (33)
- python安装包在哪里找 (33)
- linux查看python版本信息 (35)
- python怎么改成中文 (35)
- php文件怎么在浏览器运行 (33)
- eval在python中的意思 (33)
- python安装opencv库 (35)
- python div (34)
- sticky css (33)
- python中random.randint()函数 (34)
- python去掉字符串中的指定字符 (33)
- python入门经典100题 (34)
- anaconda安装路径 (34)
- yield和return的区别 (33)
- 1到10的阶乘之和是多少 (35)
- python安装sklearn库 (33)
- dom和bom区别 (33)
- js 替换指定位置的字符 (33)
- python判断元素是否存在 (33)
- sorted key (33)
- shutil.copy() (33)