一、设计模式入门:什么是设计模式、设计模式的分类、为什么要在PHP项目中使用设计模式

1.1 什么是设计模式?说白了就是“套路”

设计模式这个词,听起来挺高大上的。但说白了,它就是前辈们在长期编程实践中总结出来的一套“套路”。

我刚开始写PHP那会儿,根本不知道什么叫设计模式。项目能跑就行,管它什么模式不模式。后来有一次接手一个老项目,那代码写得……嗯,怎么说呢,一个类里面塞了三千行,一个方法里if-else嵌套了七八层。改一个需求,要翻遍十几个文件。那段时间我每天都在想:这代码到底是谁写的?后来查了下git记录——是我自己半年前写的。

从那以后,我才真正开始重视设计模式。

设计模式不是什么高深的理论。它其实就是针对特定问题的、经过验证的解决方案。打个比方:你炒菜时知道要先热锅再倒油,这就是一个“模式”。你不需要每次都重新发明轮子。

设计模式的核心价值: 让代码更容易理解、更容易扩展、更容易维护。

1.2 设计模式的三大分类

设计模式一共有23种经典模式,分为三大类。我个人习惯把它们记成:怎么创建对象、怎么组织对象、怎么让对象协作

分类 核心问题 代表模式
创建型 怎么把对象的创建过程封装起来? 单例、工厂、建造者
结构型 怎么把类和对象组合成更大的结构? 适配器、装饰器、代理
行为型 怎么让对象之间更好地通信和协作? 观察者、策略、模板方法

1.3 创建型模式:管好对象的“出生”

创建型模式解决的是“谁来创建对象”和“怎么创建对象”的问题。

你想想看,在PHP里,我们天天都在new对象。但new这个关键字有个问题:它把调用方和具体类直接绑死了。一旦你要换一个实现,就得改所有new的地方。

举个例子。我在项目中做过一个支付模块,一开始只对接了支付宝。代码里到处都是new Alipay()。后来要接入微信支付,我傻眼了——得把所有new Alipay()改成new WechatPay(),改了几十个文件,还漏了两个,线上出了bug。

如果用工厂模式,只需要改工厂里的那一行代码就行了。这就是创建型模式的价值。

我的建议: 如果你发现项目中“new”关键字出现得特别频繁,而且分散在各个类里,就该考虑用创建型模式了。

1.4 结构型模式:搭好代码的“骨架”

结构型模式关注的是类和对象的组合方式。说白了,就是怎么把各个零件拼装成一个完整的系统。

我记得有一次做一个报表系统,需要支持多种输出格式:PDF、Excel、HTML。一开始我写了一个Report类,里面塞了三个方法:exportToPdf()exportToExcel()exportToHtml()。后来要加一个CSV格式,又得改这个类。再后来要加一个图表功能……这个类越来越臃肿。

后来我用装饰器模式重构了它。核心的Report类只负责数据,输出格式用装饰器一层层包装。加新格式?写个新装饰器就行,不用动原来的代码。

结构型模式的核心思想就是:优先使用组合,而不是继承。继承是“白箱复用”,组合是“黑箱复用”。组合更灵活,耦合度更低。

1.5 行为型模式:让对象“好好说话”

行为型模式解决的是对象之间的通信问题。对象之间怎么传递消息?怎么避免紧耦合?

我做过一个电商项目,用户下单后要执行一系列操作:减库存、发邮件、更新统计、推送通知……一开始我把这些逻辑全写在OrderService::create()方法里。结果每次要加一个新操作,就得改这个方法。而且如果某个操作失败了,整个下单流程都受影响。

后来我用观察者模式重构了它。下单成功后只触发一个事件,各个观察者(减库存、发邮件等)自己去监听和处理。加新操作?写个新观察者注册上去就行。某个观察者挂了?不影响主流程。

避坑指南: 我曾经在项目里过度使用观察者模式,一个事件挂了十几个观察者,调试起来非常痛苦。后来我定了个规矩:一个事件最多挂5个观察者,超过就要考虑拆分事件。

1.6 为什么要在PHP项目中使用设计模式?

这个问题我经常被问到。有些开发者觉得PHP是脚本语言,写完了就跑,没必要搞那么复杂。嗯,这个观点我理解,但我不完全同意。

我来说说我的真实感受:

  • PHP项目越来越大了。 现在的PHP项目动辄几十万行代码,没有好的架构,维护成本会指数级上升。
  • 团队协作需要规范。 设计模式提供了一套通用的“词汇表”。你说“这里用个工厂模式”,大家都懂。你说“这里把对象的创建封装一下”,每个人理解可能不一样。
  • 框架都在用设计模式。 Laravel用了大量的设计模式:服务容器(依赖注入)、事件系统(观察者)、门面(外观模式)……不理解设计模式,你很难真正用好这些框架。
  • 面试要考。 这个比较现实,但确实是很多人的刚需。

不过我也要提醒一句:不要为了用模式而用模式。我见过有人在一个只有三个方法的类上硬套了四个设计模式,代码反而变得更复杂了。

我的原则: 先写出能跑的代码,再考虑要不要用设计模式重构。设计模式是工具,不是目的。

1.7 怎么学设计模式?

我建议你按这个顺序来:

  1. 先理解概念。 每个模式解决什么问题?核心思想是什么?
  2. 看代码示例。 不要只看UML图,要看真实的PHP代码。
  3. 在项目中找影子。 看看你现有的代码里,哪些地方可以用设计模式优化。
  4. 动手重构。 选一个你写过的、比较乱的小模块,用设计模式重构一遍。

我个人习惯是:每学一个模式,就在自己的项目里找一个对应的场景实践一下。光看不练,等于没学。

好了,这一章就到这里。下一章我们开始讲第一个具体的模式——单例模式。这个模式在PHP里特别常用,但也特别容易被滥用。到时候我会详细讲讲它的坑和正确用法。