以下是 PHP 中常用的设计模式及其典型应用场景的整理,按模式类型分类说明:


一、创建型模式(怎么“造”对象)

1. 单例模式 (Singleton)

一句话:一个类只能创建一个对象,全局共用这一个实例。
为什么用:避免重复创建对象浪费资源(数据库连接、日志、配置)。
例子:数据库连接类,全局只用一个连接,不重复连。
目的:确保一个类只有一个实例,并提供全局访问点。
场景:数据库连接、日志记录器、配置管理器。

  1. class Db
  2. {
  3. private static $instance; // 保存唯一实例
  4. // 私有化构造,禁止外部 new
  5. private function __construct() {}
  6. // 获取实例
  7. public static function getInstance()
  8. {
  9. if (!self::$instance) {
  10. self::$instance = new self();
  11. }
  12. return self::$instance;
  13. }
  14. }
  15. $db1 = Db::getInstance();
  16. $db2 = Db::getInstance();
  17. var_dump($db1 === $db2); // true 同一个对象

2. 工厂方法模式 (Factory Method)

一句话:专门造对象的工厂,你不用自己 new,告诉工厂要什么,它给你对象。 为什么用:解耦“创建对象”和“使用对象”。 例子:支付工厂 → 你说要支付宝/微信,工厂直接返回对应支付类。 目的:定义创建对象的接口,由子类决定实例化哪个类。
场景:框架中对象创建(如 HTTP 请求对象)。

  1. // 产品接口
  2. interface Pay
  3. {
  4. public function pay();
  5. }
  6. // 具体产品
  7. class AliPay implements Pay
  8. {
  9. public function pay() { echo "支付宝支付"; }
  10. }
  11. class WechatPay implements Pay
  12. {
  13. public function pay() { echo "微信支付"; }
  14. }
  15. // 工厂
  16. class PayFactory
  17. {
  18. public static function make($type)
  19. {
  20. return match ($type) {
  21. 'ali' => new AliPay(),
  22. 'wechat' => new WechatPay()
  23. };
  24. }
  25. }
  26. $pay = PayFactory::make('ali');
  27. $pay->pay(); // 支付宝支付

3. 抽象工厂(Abstract Factory)

一句话:工厂的工厂,能生产一整套相关对象
例子:电脑工厂 → 生产一套:CPU + 主板 + 内存,而不是单个零件。
和之前的工厂模式区别:工厂模式造单个对象,抽象工厂造一整套相关对象。

  1. // 抽象工厂:生产一套产品(CPU+主板)
  2. interface AbstractFactory {
  3. public function createCpu();
  4. public function createMainboard();
  5. }
  6. // 具体工厂:Intel套装
  7. class IntelFactory implements AbstractFactory {
  8. public function createCpu() { return new IntelCpu(); }
  9. public function createMainboard() { return new IntelBoard(); }
  10. }
  11. // 产品接口
  12. interface Cpu { public function run(); }
  13. interface Mainboard { public function run(); }
  14. // 具体产品
  15. class IntelCpu implements Cpu { public function run(){echo "IntelCPU运行\n";}}
  16. class IntelBoard implements Mainboard { public function run(){echo "Intel主板运行\n";}}
  17. // 使用
  18. $factory = new IntelFactory();
  19. $factory->createCpu()->run();
  20. $factory->createMainboard()->run();

4. 建造者模式 (Builder)

一句话:把复杂对象一步步拼装出来。
例子:造电脑 → 先装CPU,再装显卡,再装硬盘,最后组装成一台电脑。
目的:分步构造复杂对象,分离对象的构造与表示。
场景:生成 HTML 表单、构建 SQL 查询。

  1. class HtmlFormBuilder {
  2. private $form = [];
  3. public function addInput($name, $type) { /* ... */ }
  4. public function build() { return new Form($this->form); }
  5. }

5. 原型模式 (Prototype)

一句话:对象克隆自己,而不是重新创建。
例子:一个复杂配置好的订单对象,直接克隆一份,改个别字段就能用。
目的:通过克隆现有对象创建新对象,减少重复初始化。
场景:缓存对象、复制复杂数据结构。

  1. class User implements Cloneable {
  2. public function __clone() {
  3. // 深拷贝逻辑
  4. }
  5. }
  6. $user = new User();
  7. $cloneUser = clone $user;

二、结构型模式

6. 适配器模式 (Adapter)

一句话:把不兼容的接口转成兼容,像电源转接头。
例子:老接口返回 XML,新系统要用 JSON → 适配器转一下。
目的:使不兼容的接口能够协同工作。
场景:集成第三方库(如支付网关适配)。

  1. // 老类
  2. class OldSystem
  3. {
  4. public function oldRequest()
  5. {
  6. return "XML 数据";
  7. }
  8. }
  9. // 新接口
  10. interface NewInterface
  11. {
  12. public function request();
  13. }
  14. // 适配器
  15. class Adapter implements NewInterface
  16. {
  17. public function __construct(public OldSystem $old) {}
  18. public function request()
  19. {
  20. // 转换
  21. return str_replace("XML", "JSON", $this->old->oldRequest());
  22. }
  23. }
  24. // 使用
  25. $old = new OldSystem();
  26. $adapter = new Adapter($old);
  27. echo $adapter->request(); // JSON 数据
  28. # 以下另一示例:
  29. class PayPalAdapter implements PaymentGateway {
  30. private $paypal;
  31. public function __construct(PayPal $paypal) {
  32. $this->paypal = $paypal;
  33. }
  34. public function pay($amount) {
  35. $this->paypal->executePayment($amount);
  36. }
  37. }

7. 装饰器模式 (Decorator)

一句话不修改原类,给对象动态加功能。
例子:一杯咖啡 → 加牛奶、加糖、加冰,都是装饰,咖啡本身不变。
目的:动态地为对象添加职责。
场景:文件流处理(如压缩、加密)。

  1. interface Coffee
  2. {
  3. public function cost();
  4. }
  5. // 基础咖啡
  6. class SimpleCoffee implements Coffee
  7. {
  8. public function cost() { return 10; }
  9. }
  10. // 装饰器基类
  11. abstract class Decorator implements Coffee
  12. {
  13. public function __construct(protected Coffee $coffee) {}
  14. }
  15. // 加牛奶
  16. class Milk extends Decorator
  17. {
  18. public function cost()
  19. {
  20. return $this->coffee->cost() + 2;
  21. }
  22. }
  23. // 使用
  24. $coffee = new SimpleCoffee();
  25. $coffee = new Milk($coffee); // 装饰
  26. echo $coffee->cost(); // 12
  27. # 以下另一示例:
  28. interface Logger {
  29. public function log($message);
  30. }
  31. class FileLogger implements Logger { /* ... */ }
  32. class EncryptedLogger implements Logger {
  33. private $logger;
  34. public function __construct(Logger $logger) {
  35. $this->logger = $logger;
  36. }
  37. public function log($message) {
  38. $encrypted = encrypt($message);
  39. $this->logger->log($encrypted);
  40. }
  41. }

8. 代理模式 (Proxy)

一句话:找个中间人帮你做事,控制原对象访问。
例子

  • 日志代理:记录方法调用
  • 延迟加载:真正用到时才初始化
  • 权限控制:没权限不让调用
    目的:为其他对象提供代理以控制访问。
    场景:延迟加载大对象、权限验证。
    ```php interface User { public function getInfo(); }

// 真实类 class RealUser implements User { public function getInfo() { echo “获取用户信息”; } }

// 代理 class ProxyUser implements User { public function __construct(public RealUser $user) {}

  1. public function getInfo()
  2. {
  3. echo "权限验证\n"; // 附加功能
  4. $this->user->getInfo();
  5. }

}

// 使用 $user = new ProxyUser(new RealUser()); $user->getInfo();

以下另一示例:

class ImageProxy { private $image = null; public function display() { if ($this->image === null) { $this->image = new RealImage(“large.jpg”); } $this->image->display(); } }

  1. #### 9. 外观模式(Facade)
  2. **一句话**:给复杂系统**包一层简单入口**。
  3. **例子**:电脑开机 你只按一个键,内部CPU、内存、硬盘自动启动。
  4. ```html
  5. // 子系统
  6. class CPU
  7. {
  8. public function start() { echo "CPU启动\n"; }
  9. }
  10. class Memory
  11. {
  12. public function run() { echo "内存运行\n"; }
  13. }
  14. // 外观
  15. class Computer
  16. {
  17. public function open()
  18. {
  19. (new CPU)->start();
  20. (new Memory)->run();
  21. }
  22. }
  23. // 使用
  24. $computer = new Computer();
  25. $computer->open(); // 一键启动

10. 桥接模式(Bridge)

一句话:把两个变化维度分开,互不影响。 例子
形状(圆、方) + 颜色(红、蓝)
分开设计,自由组合:红圆、蓝方…

  1. // 维度1:颜色
  2. interface Color { public function show(); }
  3. class Red implements Color { public function show(){echo "红色";} }
  4. class Blue implements Color { public function show(){echo "蓝色";} }
  5. // 维度2:形状(桥接颜色)
  6. abstract class Shape {
  7. public function __construct(protected Color $color) {}
  8. public abstract function draw();
  9. }
  10. // 圆形
  11. class Circle extends Shape {
  12. public function draw() {
  13. $this->color->show(); echo "圆形\n";
  14. }
  15. }
  16. // 使用:任意组合
  17. $shape = new Circle(new Red());
  18. $shape->draw(); // 红色圆形

11. 组合模式 (Composite)

一句话单个对象和组合对象用起来一样
例子:文件和文件夹 → 都能“打开/删除/移动”。
目的:将对象组合成树形结构以表示“部分-整体”层次。
场景:文件系统目录结构、菜单系统。

  1. interface FileSystemComponent {
  2. public function render();
  3. }
  4. class File implements FileSystemComponent {
  5. public function render() { /* 显示文件 */ }
  6. }
  7. class Directory implements FileSystemComponent {
  8. private $children = [];
  9. public function addComponent(FileSystemComponent $c) { /* ... */ }
  10. public function render() { /* 递归渲染子项 */ }
  11. }

12. 享元模式(Flyweight)

一句话共享相同对象,节省内存
例子:围棋棋子,黑棋白棋各一个对象,无数次复用。

  1. // 享元工厂:复用棋子
  2. class PieceFactory {
  3. private static $pool = []; // 对象池
  4. public static function get($color) {
  5. if(!isset(self::$pool[$color])){
  6. self::$pool[$color] = new Piece($color);
  7. }
  8. return self::$pool[$color];
  9. }
  10. }
  11. // 享元类
  12. class Piece {
  13. public function __construct(private $color) {}
  14. public function show($x,$y){
  15. echo "{$this->color}棋在($x,$y)\n";
  16. }
  17. }
  18. // 使用:黑棋永远只有一个对象
  19. $p1 = PieceFactory::get("黑");
  20. $p2 = PieceFactory::get("黑");
  21. $p1->show(1,2);
  22. var_dump($p1===$p2); // true 同一个对象

三、行为型模式

(对象之间“怎么通信、怎么运作”)

13. 观察者模式 (Observer)

你刚才问的 TP6 事件系统就是这个!
一句话:一个对象变化,自动通知所有依赖它的对象
例子:订阅公众号 → 发文章自动推送给所有粉丝。
目的:定义对象间的一对多依赖,当一个对象状态改变时自动通知依赖者。
场景:事件监听(如用户注册后发送邮件)、日志记录。

  1. // 被观察者
  2. class Event
  3. {
  4. private $listeners = [];
  5. // 绑定监听
  6. public function attach($listener)
  7. {
  8. $this->listeners[] = $listener;
  9. }
  10. // 触发
  11. public function trigger()
  12. {
  13. foreach ($this->listeners as $l) $l->update();
  14. }
  15. }
  16. // 观察者
  17. class Listener1
  18. {
  19. public function update() { echo "记录日志\n"; }
  20. }
  21. class Listener2
  22. {
  23. public function update() { echo "发送消息\n"; }
  24. }
  25. // 使用
  26. $event = new Event();
  27. $event->attach(new Listener1());
  28. $event->attach(new Listener2());
  29. $event->trigger(); // 同时执行两个监听

14. 策略模式 (Strategy)

一句话:把不同算法封装起来,可以随时切换。
例子:支付方式 → 支付宝、微信、银行卡,随时切换,逻辑互不干扰。
目的:定义一系列算法并使其可互换。
场景:支付方式切换(支付宝/微信)、排序算法选择。

  1. interface Strategy
  2. {
  3. public function calc($a, $b);
  4. }
  5. // 策略A
  6. class Add implements Strategy
  7. {
  8. public function calc($a, $b) { return $a + $b; }
  9. }
  10. // 策略B
  11. class Sub implements Strategy
  12. {
  13. public function calc($a, $b) { return $a - $b; }
  14. }
  15. // 环境类
  16. class Context
  17. {
  18. public function __construct(public Strategy $strategy) {}
  19. public function exec($a, $b)
  20. {
  21. return $this->strategy->calc($a, $b);
  22. }
  23. }
  24. // 切换策略
  25. $ctx = new Context(new Add());
  26. echo $ctx->exec(5, 3); // 8
  27. $ctx = new Context(new Sub());
  28. echo $ctx->exec(5, 3); // 2
  29. # 以下另一示例:
  30. interface SortStrategy {
  31. public function sort(array $data);
  32. }
  33. class QuickSort implements SortStrategy { /* ... */ }
  34. class Sorter {
  35. private $strategy;
  36. public function setStrategy(SortStrategy $s) { $this->strategy = $s; }
  37. public function execute(array $data) { return $this->strategy->sort($data); }
  38. }

15. 命令模式 (Command)

一句话:把请求封装成命令对象,可记录、可撤销、可排队。
例子:遥控器按钮 → 每个按钮是一个命令,可撤销操作。
目的:将请求封装为对象,以便参数化、队列化或记录请求。
场景:任务队列、事务回滚、宏命令。

  1. interface Command {
  2. public function execute();
  3. }
  4. class CreateUserCommand implements Command {
  5. private $userService;
  6. public function execute() { $this->userService->create(); }
  7. }
  8. class CommandQueue {
  9. private $commands = [];
  10. public function add(Command $c) { $this->commands[] = $c; }
  11. public function process() { foreach ($this->commands as $c) $c->execute(); }
  12. }

16. 迭代器模式(Iterator)

一句话:不暴露集合内部结构,按顺序遍历元素。安全遍历集合,不暴露内部结构。PHP 内置支持,最常用。
例子:PHP 的 foreach 就是迭代器。

  1. // 自定义集合
  2. class ListCollection implements IteratorAggregate {
  3. private $items = ['A','B','C'];
  4. // 返回迭代器
  5. public function getIterator() {
  6. return new ArrayIterator($this->items);
  7. }
  8. }
  9. // 使用:foreach 就是迭代器
  10. $list = new ListCollection();
  11. foreach($list as $v) echo $v."\n";

17. 责任链模式 (Chain of Responsibility)

一句话:请求顺着一条链传递,直到有人处理它。
例子:请假审批 → 组长 → 经理 → 总监,一层层传递。
目的:使多个对象都有机会处理请求,避免请求发送者与接收者耦合。
场景:中间件管道(如 Laravel 中间件)、审批流程。

  1. abstract class Handler
  2. {
  3. protected $next;
  4. public function setNext($next)
  5. {
  6. $this->next = $next;
  7. }
  8. abstract public function handle($day);
  9. }
  10. // 组长
  11. class Leader extends Handler
  12. {
  13. public function handle($day)
  14. {
  15. if ($day <= 1) echo "组长批准\n";
  16. else $this->next->handle($day);
  17. }
  18. }
  19. // 经理
  20. class Manager extends Handler
  21. {
  22. public function handle($day)
  23. {
  24. if ($day <= 3) echo "经理批准\n";
  25. else echo "总监批准\n";
  26. }
  27. }
  28. // 使用
  29. $leader = new Leader();
  30. $manager = new Manager();
  31. $leader->setNext($manager);
  32. $leader->handle(2); // 经理批准
  33. # 以下另一示例:
  34. abstract class Middleware {
  35. protected $next;
  36. public function setNext(Middleware $m) { $this->next = $m; }
  37. public function handle($request) {
  38. if ($this->next) return $this->next->handle($request);
  39. }
  40. }
  41. class AuthMiddleware extends Middleware {
  42. public function handle($request) {
  43. if (!auth()->check()) throw new UnauthorizedException();
  44. parent::handle($request);
  45. }
  46. }

18. 模板方法模式(Template)

一句话:定义固定流程骨架,具体步骤子类实现。
例子:做咖啡流程:烧水 → 冲泡 → 加调料 → 完成,流程固定,调料不同。

  1. abstract class MakeDrink
  2. {
  3. // 模板:固定流程
  4. public final function make()
  5. {
  6. $this->boil();
  7. $this->brew();
  8. $this->add();
  9. }
  10. public function boil() { echo "烧水\n"; }
  11. abstract public function brew();
  12. abstract public function add();
  13. }
  14. // 咖啡
  15. class Coffee extends MakeDrink
  16. {
  17. public function brew() { echo "冲泡咖啡\n"; }
  18. public function add() { echo "加糖\n"; }
  19. }
  20. // 使用
  21. $drink = new Coffee();
  22. $drink->make();

19. 状态模式(State)

一句话:对象内部状态改变,行为就改变。,不用大量 if/else。
例子:订单状态:待付款 → 已付款 → 已发货 → 完成,状态不同行为不同。

  1. // 状态接口
  2. interface State { public function handle(Order $order); }
  3. // 订单
  4. class Order {
  5. private $state;
  6. public function setState(State $state){$this->state=$state;}
  7. public function do(){ $this->state->handle($this); }
  8. }
  9. // 具体状态
  10. class PayState implements State {
  11. public function handle(Order $order){echo "已付款\n";}
  12. }
  13. class ShipState implements State {
  14. public function handle(Order $order){echo "已发货\n";}
  15. }
  16. // 使用:切换状态自动变行为
  17. $order = new Order();
  18. $order->setState(new PayState());
  19. $order->do(); // 已付款

20. 中介者模式(Mediator)

一句话:对象之间不直接通信,通过中介交互。
例子:聊天室 → 大家不私聊,都发给服务器,服务器转发。

  1. // 中介者:聊天室
  2. class ChatRoom {
  3. public static function send(User $user, $msg) {
  4. echo $user->name.":".$msg."\n";
  5. }
  6. }
  7. // 用户
  8. class User {
  9. public function __construct(public $name) {}
  10. public function send($msg) {
  11. ChatRoom::send($this, $msg);
  12. }
  13. }
  14. // 使用:不直接私聊
  15. $u1 = new User("张三");
  16. $u2 = new User("李四");
  17. $u1->send("你好"); // 张三:你好

21. 访问者模式(Visitor)

一句话不改变数据结构,给结构增加新操作。或不修改类,给类增加新功能。
例子:一个商品列表,增加“计算总价”“导出报表”等功能。

  1. // 访问者
  2. interface Visitor { public function visit(Product $p); }
  3. class PriceVisitor implements Visitor {
  4. public function visit(Product $p) {echo "价格:".$p->price."\n";}
  5. }
  6. // 元素
  7. class Product {
  8. public function __construct(public $price) {}
  9. public function accept(Visitor $v) {$v->visit($this);}
  10. }
  11. // 使用
  12. $p = new Product(99);
  13. $p->accept(new PriceVisitor()); // 打印价格

22. 备忘录模式(Memento)

一句话:保存对象某个时刻状态,需要时恢复。或保存状态,可撤销 / 回滚。
例子:游戏存档、编辑器撤销(Ctrl+Z)。

  1. // 备忘录:保存状态
  2. class Memento {
  3. public function __construct(public $state) {}
  4. }
  5. // 原发器
  6. class Editor {
  7. private $content;
  8. public function set($c) {$this->content=$c;}
  9. public function save() {return new Memento($this->content);}
  10. public function restore($m) {$this->content=$m->state;}
  11. }
  12. // 使用
  13. $e = new Editor();
  14. $e->set("版本1");
  15. $backup = $e->save(); // 存档
  16. $e->set("版本2");
  17. $e->restore($backup); // 回滚到版本1

23. 解释器模式(Interpreter)

一句话:自定义语法规则,自己解析执行。
例子:简单计算器、规则引擎、表达式判断。

  1. // 解释器
  2. class Context {
  3. public function __construct(public $input) {}
  4. }
  5. // 规则:判断是否包含
  6. class ContainsExp {
  7. public function __construct(private $key) {}
  8. public function interpret(Context $ctx) {
  9. return str_contains($ctx->input, $this->key);
  10. }
  11. }
  12. // 使用
  13. $ctx = new Context("HelloWorld");
  14. $exp = new ContainsExp("Hello");
  15. var_dump($exp->interpret($ctx)); // true

四、超简记忆口诀(你记这个就够)

  • 创建型:怎么new对象(单例、工厂、建造者)
  • 结构型:怎么组合代码(适配器、装饰器、代理、外观)
  • 行为型:对象怎么通信(观察者、策略、责任链、命令)

五、如何选择设计模式?

  1. 解耦需求:当系统需要降低模块间耦合时(如观察者模式)。
  2. 复用与扩展:需灵活扩展功能时(如装饰器模式)。
  3. 复杂流程控制:如状态模式管理订单生命周期。
  4. 代码可维护性:如策略模式替代条件分支(switch-case)。

通过合理使用设计模式,可以提升代码的可维护性、扩展性和复用性,但需避免过度设计。