以下是 PHP 中常用的设计模式及其典型应用场景的整理,按模式类型分类说明:
一、创建型模式(怎么“造”对象)
1. 单例模式 (Singleton)
一句话:一个类只能创建一个对象,全局共用这一个实例。
为什么用:避免重复创建对象浪费资源(数据库连接、日志、配置)。
例子:数据库连接类,全局只用一个连接,不重复连。
目的:确保一个类只有一个实例,并提供全局访问点。
场景:数据库连接、日志记录器、配置管理器。
class Db{private static $instance; // 保存唯一实例// 私有化构造,禁止外部 newprivate function __construct() {}// 获取实例public static function getInstance(){if (!self::$instance) {self::$instance = new self();}return self::$instance;}}$db1 = Db::getInstance();$db2 = Db::getInstance();var_dump($db1 === $db2); // true 同一个对象
2. 工厂方法模式 (Factory Method)
一句话:专门造对象的工厂,你不用自己 new,告诉工厂要什么,它给你对象。
为什么用:解耦“创建对象”和“使用对象”。
例子:支付工厂 → 你说要支付宝/微信,工厂直接返回对应支付类。
目的:定义创建对象的接口,由子类决定实例化哪个类。
场景:框架中对象创建(如 HTTP 请求对象)。
// 产品接口interface Pay{public function pay();}// 具体产品class AliPay implements Pay{public function pay() { echo "支付宝支付"; }}class WechatPay implements Pay{public function pay() { echo "微信支付"; }}// 工厂class PayFactory{public static function make($type){return match ($type) {'ali' => new AliPay(),'wechat' => new WechatPay()};}}$pay = PayFactory::make('ali');$pay->pay(); // 支付宝支付
3. 抽象工厂(Abstract Factory)
一句话:工厂的工厂,能生产一整套相关对象。
例子:电脑工厂 → 生产一套:CPU + 主板 + 内存,而不是单个零件。
和之前的工厂模式区别:工厂模式造单个对象,抽象工厂造一整套相关对象。
// 抽象工厂:生产一套产品(CPU+主板)interface AbstractFactory {public function createCpu();public function createMainboard();}// 具体工厂:Intel套装class IntelFactory implements AbstractFactory {public function createCpu() { return new IntelCpu(); }public function createMainboard() { return new IntelBoard(); }}// 产品接口interface Cpu { public function run(); }interface Mainboard { public function run(); }// 具体产品class IntelCpu implements Cpu { public function run(){echo "IntelCPU运行\n";}}class IntelBoard implements Mainboard { public function run(){echo "Intel主板运行\n";}}// 使用$factory = new IntelFactory();$factory->createCpu()->run();$factory->createMainboard()->run();
4. 建造者模式 (Builder)
一句话:把复杂对象一步步拼装出来。
例子:造电脑 → 先装CPU,再装显卡,再装硬盘,最后组装成一台电脑。
目的:分步构造复杂对象,分离对象的构造与表示。
场景:生成 HTML 表单、构建 SQL 查询。
class HtmlFormBuilder {private $form = [];public function addInput($name, $type) { /* ... */ }public function build() { return new Form($this->form); }}
5. 原型模式 (Prototype)
一句话:对象克隆自己,而不是重新创建。
例子:一个复杂配置好的订单对象,直接克隆一份,改个别字段就能用。
目的:通过克隆现有对象创建新对象,减少重复初始化。
场景:缓存对象、复制复杂数据结构。
class User implements Cloneable {public function __clone() {// 深拷贝逻辑}}$user = new User();$cloneUser = clone $user;
二、结构型模式
6. 适配器模式 (Adapter)
一句话:把不兼容的接口转成兼容,像电源转接头。
例子:老接口返回 XML,新系统要用 JSON → 适配器转一下。
目的:使不兼容的接口能够协同工作。
场景:集成第三方库(如支付网关适配)。
// 老类class OldSystem{public function oldRequest(){return "XML 数据";}}// 新接口interface NewInterface{public function request();}// 适配器class Adapter implements NewInterface{public function __construct(public OldSystem $old) {}public function request(){// 转换return str_replace("XML", "JSON", $this->old->oldRequest());}}// 使用$old = new OldSystem();$adapter = new Adapter($old);echo $adapter->request(); // JSON 数据# 以下另一示例:class PayPalAdapter implements PaymentGateway {private $paypal;public function __construct(PayPal $paypal) {$this->paypal = $paypal;}public function pay($amount) {$this->paypal->executePayment($amount);}}
7. 装饰器模式 (Decorator)
一句话:不修改原类,给对象动态加功能。
例子:一杯咖啡 → 加牛奶、加糖、加冰,都是装饰,咖啡本身不变。
目的:动态地为对象添加职责。
场景:文件流处理(如压缩、加密)。
interface Coffee{public function cost();}// 基础咖啡class SimpleCoffee implements Coffee{public function cost() { return 10; }}// 装饰器基类abstract class Decorator implements Coffee{public function __construct(protected Coffee $coffee) {}}// 加牛奶class Milk extends Decorator{public function cost(){return $this->coffee->cost() + 2;}}// 使用$coffee = new SimpleCoffee();$coffee = new Milk($coffee); // 装饰echo $coffee->cost(); // 12# 以下另一示例:interface Logger {public function log($message);}class FileLogger implements Logger { /* ... */ }class EncryptedLogger implements Logger {private $logger;public function __construct(Logger $logger) {$this->logger = $logger;}public function log($message) {$encrypted = encrypt($message);$this->logger->log($encrypted);}}
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) {}
public function getInfo(){echo "权限验证\n"; // 附加功能$this->user->getInfo();}
}
// 使用 $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(); } }
#### 9. 外观模式(Facade)**一句话**:给复杂系统**包一层简单入口**。**例子**:电脑开机 → 你只按一个键,内部CPU、内存、硬盘自动启动。```html// 子系统class CPU{public function start() { echo "CPU启动\n"; }}class Memory{public function run() { echo "内存运行\n"; }}// 外观class Computer{public function open(){(new CPU)->start();(new Memory)->run();}}// 使用$computer = new Computer();$computer->open(); // 一键启动
10. 桥接模式(Bridge)
一句话:把两个变化维度分开,互不影响。
例子:
形状(圆、方) + 颜色(红、蓝)
分开设计,自由组合:红圆、蓝方…
// 维度1:颜色interface Color { public function show(); }class Red implements Color { public function show(){echo "红色";} }class Blue implements Color { public function show(){echo "蓝色";} }// 维度2:形状(桥接颜色)abstract class Shape {public function __construct(protected Color $color) {}public abstract function draw();}// 圆形class Circle extends Shape {public function draw() {$this->color->show(); echo "圆形\n";}}// 使用:任意组合$shape = new Circle(new Red());$shape->draw(); // 红色圆形
11. 组合模式 (Composite)
一句话:单个对象和组合对象用起来一样。
例子:文件和文件夹 → 都能“打开/删除/移动”。
目的:将对象组合成树形结构以表示“部分-整体”层次。
场景:文件系统目录结构、菜单系统。
interface FileSystemComponent {public function render();}class File implements FileSystemComponent {public function render() { /* 显示文件 */ }}class Directory implements FileSystemComponent {private $children = [];public function addComponent(FileSystemComponent $c) { /* ... */ }public function render() { /* 递归渲染子项 */ }}
12. 享元模式(Flyweight)
一句话:共享相同对象,节省内存。
例子:围棋棋子,黑棋白棋各一个对象,无数次复用。
// 享元工厂:复用棋子class PieceFactory {private static $pool = []; // 对象池public static function get($color) {if(!isset(self::$pool[$color])){self::$pool[$color] = new Piece($color);}return self::$pool[$color];}}// 享元类class Piece {public function __construct(private $color) {}public function show($x,$y){echo "{$this->color}棋在($x,$y)\n";}}// 使用:黑棋永远只有一个对象$p1 = PieceFactory::get("黑");$p2 = PieceFactory::get("黑");$p1->show(1,2);var_dump($p1===$p2); // true 同一个对象
三、行为型模式
(对象之间“怎么通信、怎么运作”)
13. 观察者模式 (Observer)
你刚才问的 TP6 事件系统就是这个!
一句话:一个对象变化,自动通知所有依赖它的对象。
例子:订阅公众号 → 发文章自动推送给所有粉丝。
目的:定义对象间的一对多依赖,当一个对象状态改变时自动通知依赖者。
场景:事件监听(如用户注册后发送邮件)、日志记录。
// 被观察者class Event{private $listeners = [];// 绑定监听public function attach($listener){$this->listeners[] = $listener;}// 触发public function trigger(){foreach ($this->listeners as $l) $l->update();}}// 观察者class Listener1{public function update() { echo "记录日志\n"; }}class Listener2{public function update() { echo "发送消息\n"; }}// 使用$event = new Event();$event->attach(new Listener1());$event->attach(new Listener2());$event->trigger(); // 同时执行两个监听
14. 策略模式 (Strategy)
一句话:把不同算法封装起来,可以随时切换。
例子:支付方式 → 支付宝、微信、银行卡,随时切换,逻辑互不干扰。
目的:定义一系列算法并使其可互换。
场景:支付方式切换(支付宝/微信)、排序算法选择。
interface Strategy{public function calc($a, $b);}// 策略Aclass Add implements Strategy{public function calc($a, $b) { return $a + $b; }}// 策略Bclass Sub implements Strategy{public function calc($a, $b) { return $a - $b; }}// 环境类class Context{public function __construct(public Strategy $strategy) {}public function exec($a, $b){return $this->strategy->calc($a, $b);}}// 切换策略$ctx = new Context(new Add());echo $ctx->exec(5, 3); // 8$ctx = new Context(new Sub());echo $ctx->exec(5, 3); // 2# 以下另一示例:interface SortStrategy {public function sort(array $data);}class QuickSort implements SortStrategy { /* ... */ }class Sorter {private $strategy;public function setStrategy(SortStrategy $s) { $this->strategy = $s; }public function execute(array $data) { return $this->strategy->sort($data); }}
15. 命令模式 (Command)
一句话:把请求封装成命令对象,可记录、可撤销、可排队。
例子:遥控器按钮 → 每个按钮是一个命令,可撤销操作。
目的:将请求封装为对象,以便参数化、队列化或记录请求。
场景:任务队列、事务回滚、宏命令。
interface Command {public function execute();}class CreateUserCommand implements Command {private $userService;public function execute() { $this->userService->create(); }}class CommandQueue {private $commands = [];public function add(Command $c) { $this->commands[] = $c; }public function process() { foreach ($this->commands as $c) $c->execute(); }}
16. 迭代器模式(Iterator)
一句话:不暴露集合内部结构,按顺序遍历元素。安全遍历集合,不暴露内部结构。PHP 内置支持,最常用。
例子:PHP 的 foreach 就是迭代器。
// 自定义集合class ListCollection implements IteratorAggregate {private $items = ['A','B','C'];// 返回迭代器public function getIterator() {return new ArrayIterator($this->items);}}// 使用:foreach 就是迭代器$list = new ListCollection();foreach($list as $v) echo $v."\n";
17. 责任链模式 (Chain of Responsibility)
一句话:请求顺着一条链传递,直到有人处理它。
例子:请假审批 → 组长 → 经理 → 总监,一层层传递。
目的:使多个对象都有机会处理请求,避免请求发送者与接收者耦合。
场景:中间件管道(如 Laravel 中间件)、审批流程。
abstract class Handler{protected $next;public function setNext($next){$this->next = $next;}abstract public function handle($day);}// 组长class Leader extends Handler{public function handle($day){if ($day <= 1) echo "组长批准\n";else $this->next->handle($day);}}// 经理class Manager extends Handler{public function handle($day){if ($day <= 3) echo "经理批准\n";else echo "总监批准\n";}}// 使用$leader = new Leader();$manager = new Manager();$leader->setNext($manager);$leader->handle(2); // 经理批准# 以下另一示例:abstract class Middleware {protected $next;public function setNext(Middleware $m) { $this->next = $m; }public function handle($request) {if ($this->next) return $this->next->handle($request);}}class AuthMiddleware extends Middleware {public function handle($request) {if (!auth()->check()) throw new UnauthorizedException();parent::handle($request);}}
18. 模板方法模式(Template)
一句话:定义固定流程骨架,具体步骤子类实现。
例子:做咖啡流程:烧水 → 冲泡 → 加调料 → 完成,流程固定,调料不同。
abstract class MakeDrink{// 模板:固定流程public final function make(){$this->boil();$this->brew();$this->add();}public function boil() { echo "烧水\n"; }abstract public function brew();abstract public function add();}// 咖啡class Coffee extends MakeDrink{public function brew() { echo "冲泡咖啡\n"; }public function add() { echo "加糖\n"; }}// 使用$drink = new Coffee();$drink->make();
19. 状态模式(State)
一句话:对象内部状态改变,行为就改变。,不用大量 if/else。
例子:订单状态:待付款 → 已付款 → 已发货 → 完成,状态不同行为不同。
// 状态接口interface State { public function handle(Order $order); }// 订单class Order {private $state;public function setState(State $state){$this->state=$state;}public function do(){ $this->state->handle($this); }}// 具体状态class PayState implements State {public function handle(Order $order){echo "已付款\n";}}class ShipState implements State {public function handle(Order $order){echo "已发货\n";}}// 使用:切换状态自动变行为$order = new Order();$order->setState(new PayState());$order->do(); // 已付款
20. 中介者模式(Mediator)
一句话:对象之间不直接通信,通过中介交互。
例子:聊天室 → 大家不私聊,都发给服务器,服务器转发。
// 中介者:聊天室class ChatRoom {public static function send(User $user, $msg) {echo $user->name.":".$msg."\n";}}// 用户class User {public function __construct(public $name) {}public function send($msg) {ChatRoom::send($this, $msg);}}// 使用:不直接私聊$u1 = new User("张三");$u2 = new User("李四");$u1->send("你好"); // 张三:你好
21. 访问者模式(Visitor)
一句话:不改变数据结构,给结构增加新操作。或不修改类,给类增加新功能。
例子:一个商品列表,增加“计算总价”“导出报表”等功能。
// 访问者interface Visitor { public function visit(Product $p); }class PriceVisitor implements Visitor {public function visit(Product $p) {echo "价格:".$p->price."\n";}}// 元素class Product {public function __construct(public $price) {}public function accept(Visitor $v) {$v->visit($this);}}// 使用$p = new Product(99);$p->accept(new PriceVisitor()); // 打印价格
22. 备忘录模式(Memento)
一句话:保存对象某个时刻状态,需要时恢复。或保存状态,可撤销 / 回滚。
例子:游戏存档、编辑器撤销(Ctrl+Z)。
// 备忘录:保存状态class Memento {public function __construct(public $state) {}}// 原发器class Editor {private $content;public function set($c) {$this->content=$c;}public function save() {return new Memento($this->content);}public function restore($m) {$this->content=$m->state;}}// 使用$e = new Editor();$e->set("版本1");$backup = $e->save(); // 存档$e->set("版本2");$e->restore($backup); // 回滚到版本1
23. 解释器模式(Interpreter)
一句话:自定义语法规则,自己解析执行。
例子:简单计算器、规则引擎、表达式判断。
// 解释器class Context {public function __construct(public $input) {}}// 规则:判断是否包含class ContainsExp {public function __construct(private $key) {}public function interpret(Context $ctx) {return str_contains($ctx->input, $this->key);}}// 使用$ctx = new Context("HelloWorld");$exp = new ContainsExp("Hello");var_dump($exp->interpret($ctx)); // true
四、超简记忆口诀(你记这个就够)
- 创建型:怎么new对象(单例、工厂、建造者)
- 结构型:怎么组合代码(适配器、装饰器、代理、外观)
- 行为型:对象怎么通信(观察者、策略、责任链、命令)
五、如何选择设计模式?
- 解耦需求:当系统需要降低模块间耦合时(如观察者模式)。
- 复用与扩展:需灵活扩展功能时(如装饰器模式)。
- 复杂流程控制:如状态模式管理订单生命周期。
- 代码可维护性:如策略模式替代条件分支(switch-case)。
通过合理使用设计模式,可以提升代码的可维护性、扩展性和复用性,但需避免过度设计。
