1. 设计模式概述设计模式Design Pattern是软件设计中常见问题的典型、可复用的解决方案。它不是可以直接转换成代码的完整设计而是一种模板描述了在特定场景下如何解决一个通用设计问题。在 PHP 开发中合理运用设计模式可以带来以下好处提升代码可维护性模式化的代码结构清晰易于理解和修改。增强代码复用性避免重复造轮子提高开发效率。降低模块耦合度通过抽象和接口使组件之间依赖更清晰、更松散。提高团队协作效率提供一套通用的设计“词汇表”便于沟通。PHP 作为一门成熟的面向对象语言完全支持经典设计模式的实现。本文将带你系统学习 PHP 中常用的设计模式并结合实际代码示例助你写出更优雅、健壮的代码。2. 创建型模式Creational Patterns创建型模式关注对象的创建机制旨在以更灵活、更符合业务逻辑的方式创建对象而不是直接使用new关键字。2.1 单例模式Singleton意图确保一个类只有一个实例并提供一个全局访问点。适用场景数据库连接、日志记录器、配置管理器等需要全局唯一实例的资源。PHP 实现示例?phpclassDatabaseConnection{privatestatic?self$instancenull;private\PDO$connection;// 私有化构造函数防止外部实例化privatefunction__construct(){$this-connectionnew\PDO(mysql:hostlocalhost;dbnametest,username,password);}// 防止克隆privatefunction__clone(){}// 防止反序列化创建新实例publicfunction__wakeup(){thrownew\Exception(Cannot unserialize singleton);}publicstaticfunctiongetInstance():self{if(self::$instancenull){self::$instancenewself();}returnself::$instance;}publicfunctiongetConnection():\PDO{return$this-connection;}}// 使用$db1DatabaseConnection::getInstance();$db2DatabaseConnection::getInstance();var_dump($db1$db2);// bool(true)?2.2 工厂方法模式Factory Method意图定义一个用于创建对象的接口但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。适用场景在电商或金融系统中根据用户选择的支付方式如支付宝、微信支付、银联动态创建对应的支付网关处理器对象。?phpinterfaceLogger{publicfunctionlog(string$message):void;}classFileLoggerimplementsLogger{publicfunctionlog(string$message):void{file_put_contents(app.log,$message.PHP_EOL,FILE_APPEND);}}classDatabaseLoggerimplementsLogger{publicfunctionlog(string$message):void{// 模拟写入数据库echoLog to database:$message.PHP_EOL;}}abstractclassLoggerFactory{abstractpublicfunctioncreateLogger():Logger;publicfunctionlogMessage(string$message):void{$logger$this-createLogger();$logger-log($message);}}classFileLoggerFactoryextendsLoggerFactory{publicfunctioncreateLogger():Logger{returnnewFileLogger();}}classDatabaseLoggerFactoryextendsLoggerFactory{publicfunctioncreateLogger():Logger{returnnewDatabaseLogger();}}// 使用$factorynewFileLoggerFactory();$factory-logMessage(This is a file log.);?3. 结构型模式Structural Patterns结构型模式关注如何将类或对象组合成更大的结构同时保持结构的灵活和高效。3.1 适配器模式Adapter意图将一个类的接口转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以一起工作。适用场景集成第三方库、旧系统改造、统一多个不同接口。PHP 实现示例?php// 已有的、不兼容的类classOldLogger{publicfunctionwriteToLog(string$msg):void{echoOld Logger:$msg.PHP_EOL;}}// 期望的新接口interfaceNewLoggerInterface{publicfunctionlog(string$message,string$levelINFO):void;}// 适配器类classLoggerAdapterimplementsNewLoggerInterface{privateOldLogger$oldLogger;publicfunction__construct(OldLogger$oldLogger){$this-oldLogger$oldLogger;}publicfunctionlog(string$message,string$levelINFO):void{// 适配过程将新接口的参数转换为旧类的方法调用$formattedMessage[$level]$message;$this-oldLogger-writeToLog($formattedMessage);}}// 使用新接口的客户端代码functionclientCode(NewLoggerInterface$logger):void{$logger-log(User logged in,INFO);$logger-log(Payment failed,ERROR);}$oldLoggernewOldLogger();$adapternewLoggerAdapter($oldLogger);clientCode($adapter);?3.2 装饰器模式Decorator意图动态地给一个对象添加一些额外的职责。就增加功能来说装饰器模式比生成子类更为灵活。适用场景需要在不修改原有对象结构的情况下透明地、动态地扩展对象的功能。PHP 实现示例?phpinterfaceCoffee{publicfunctiongetCost():float;publicfunctiongetDescription():string;}classSimpleCoffeeimplementsCoffee{publicfunctiongetCost():float{return10.0;}publicfunctiongetDescription():string{returnSimple coffee;}}// 装饰器抽象类abstractclassCoffeeDecoratorimplementsCoffee{protectedCoffee$coffee;publicfunction__construct(Coffee$coffee){$this-coffee$coffee;}publicfunctiongetCost():float{return$this-coffee-getCost();}publicfunctiongetDescription():string{return$this-coffee-getDescription();}}// 具体装饰器加牛奶classMilkDecoratorextendsCoffeeDecorator{publicfunctiongetCost():float{returnparent::getCost()2.0;}publicfunctiongetDescription():string{returnparent::getDescription()., milk;}}// 具体装饰器加糖classSugarDecoratorextendsCoffeeDecorator{publicfunctiongetCost():float{returnparent::getCost()1.0;}publicfunctiongetDescription():string{returnparent::getDescription()., sugar;}}// 使用$coffeenewSimpleCoffee();echo$coffee-getDescription(). costs $.$coffee-getCost().PHP_EOL;$coffeeWithMilknewMilkDecorator($coffee);echo$coffeeWithMilk-getDescription(). costs $.$coffeeWithMilk-getCost().PHP_EOL;$coffeeWithMilkAndSugarnewSugarDecorator($coffeeWithMilk);echo$coffeeWithMilkAndSugar-getDescription(). costs $.$coffeeWithMilkAndSugar-getCost().PHP_EOL;?4. 行为型模式Behavioral Patterns行为型模式关注对象之间的职责分配和算法封装描述类或对象怎样交互以及怎样分配职责。4.1 观察者模式Observer意图定义对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都得到通知并被自动更新。适用场景事件驱动系统、消息队列、GUI 事件处理、发布-订阅模型。PHP 实现示例使用 SPL 内置接口?php// 被观察者主题classUserLoginimplements\SplSubject{private\SplObjectStorage$observers;privatestring$username;privatestring$ipAddress;publicfunction__construct(string$username,string$ipAddress){$this-observersnew\SplObjectStorage();$this-username$username;$this-ipAddress$ipAddress;}publicfunctionattach(\SplObserver$observer):void{$this-observers-attach($observer);}publicfunctiondetach(\SplObserver$observer):void{$this-observers-detach($observer);}publicfunctionnotify():void{foreach($this-observersas$observer){$observer-update($this);}}publicfunctionlogin():void{// 模拟登录逻辑echoUser{$this-username}logged in from{$this-ipAddress}.\n;$this-notify();// 状态改变通知所有观察者}publicfunctiongetUsername():string{return$this-username;}publicfunctiongetIpAddress():string{return$this-ipAddress;}}// 观察者日志记录classLoginLoggerimplements\SplObserver{publicfunctionupdate(\SplSubject$subject):void{if($subjectinstanceofUserLogin){$logMessagesprintf([%s] User %s logged in from %s\n,date(Y-m-d H:i:s),$subject-getUsername(),$subject-getIpAddress());file_put_contents(login.log,$logMessage,FILE_APPEND);echoLoginLogger: Logged the event.\n;}}}// 观察者发送邮件通知classEmailNotifierimplements\SplObserver{publicfunctionupdate(\SplSubject$subject):void{if($subjectinstanceofUserLogin){// 模拟发送邮件echoEmailNotifier: Sent login alert email for user{$subject-getUsername()}.\n;}}}// 使用$userLoginnewUserLogin(john_doe,192.168.1.100);$userLogin-attach(newLoginLogger());$userLogin-attach(newEmailNotifier());$userLogin-login();?4.2 策略模式Strategy意图定义一系列算法将每个算法封装起来并使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。适用场景需要动态地在多种算法中选择一种、避免使用多重条件判断语句。PHP 实现示例?phpinterfacePaymentStrategy{publicfunctionpay(float$amount):void;}classCreditCardPaymentimplementsPaymentStrategy{privatestring$cardNumber;privatestring$cvv;publicfunction__construct(string$cardNumber,string$cvv){$this-cardNumber$cardNumber;$this-cvv$cvv;}publicfunctionpay(float$amount):void{echoPaying$$amountusing Credit Card ending in .substr($this-cardNumber,-4)..\n;// 实际支付逻辑...}}classPayPalPaymentimplementsPaymentStrategy{privatestring$email;publicfunction__construct(string$email){$this-email$email;}publicfunctionpay(float$amount):void{echoPaying$$amountusing PayPal account{$this-email}.\n;// 实际支付逻辑...}}classCryptoPaymentimplementsPaymentStrategy{privatestring$walletAddress;publicfunction__construct(string$walletAddress){$this-walletAddress$walletAddress;}publicfunctionpay(float$amount):void{echoPaying$$amountusing Crypto wallet{$this-walletAddress}.\n;// 实际支付逻辑...}}// 上下文类classShoppingCart{privatePaymentStrategy$paymentStrategy;publicfunctionsetPaymentStrategy(PaymentStrategy$strategy):void{$this-paymentStrategy$strategy;}publicfunctioncheckout(float$amount):void{if(!isset($this-paymentStrategy)){thrownew\RuntimeException(Payment strategy not set.);}$this-paymentStrategy-pay($amount);}}// 使用$cartnewShoppingCart();$cart-setPaymentStrategy(newCreditCardPayment(4111111111111111,123));$cart-checkout(100.50);$cart-setPaymentStrategy(newPayPalPayment(userexample.com));$cart-checkout(75.25);?