PHP设计模式——行为型模式
PHP 设计模式中的行为模式(Behavioral Patterns)主要关注对象之间的通信和交互。行为模式的目的是在不暴露对象之间的具体通信细节的情况下,定义对象的行为和职责。它们常用于解决对象如何协调工作的问题,提高系统的灵活性、可扩展性和可维护性。
1、策略模式(Strategy Pattern)
概述
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以互相替换,该模式使得算法可以独立于使用它的客户端变化。也就是说,测策略模式让一个类的行为可以在运行时被改变,从而实现不同的业务逻辑。
结构
策略模式的结构通常包含以下几个组成部分:
1、Context(环境类):
维护一个指向具体策略类的引用。
向客户端暴露一个公共的接口,用于调用具体的策略行为
2、Strategy(策略接口):
定义一个统一的策略接口,通常是一个抽象类或者接口,所有具体策略类都实现这个接口,包含算法的具体实现。
3、ConcreteStrategy(具体策略类):
实现策略接口中的算法
实例
以一个简单的支付系统为例,假设用户可以选择不同的支付方式(如支付宝、微信支付、信用卡支付等),我们可以使用策略模式来实现。
// 策略接口
public interface PaymentStrategy {
void pay(int amount);
}
// 具体策略:支付宝支付
public class AlipayStrategy implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("使用支付宝支付 " + amount + " 元");
}
}
// 具体策略:微信支付
public class WeChatPayStrategy implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("使用微信支付 " + amount + " 元");
}
}
// 具体策略:信用卡支付
public class CreditCardStrategy implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("使用信用卡支付 " + amount + " 元");
}
}
// 上下文类
public class PaymentContext {
private PaymentStrategy paymentStrategy;
// 通过构造器或setter方法注入具体策略
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// 执行支付
public void executePayment(int amount) {
paymentStrategy.pay(amount);
}
// 设置不同的支付策略
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建不同的支付策略
PaymentStrategy alipay = new AlipayStrategy();
PaymentStrategy weChatPay = new WeChatPayStrategy();
PaymentStrategy creditCard = new CreditCardStrategy();
// 创建上下文,选择支付方式
PaymentContext context = new PaymentContext(alipay);
context.executePayment(100);
// 改变支付策略
context.setPaymentStrategy(weChatPay);
context.executePayment(200);
context.setPaymentStrategy(creditCard);
context.executePayment(300);
}
}
运行结果
使用支付宝支付 100 元
使用微信支付 200 元
使用信用卡支付 300 元
适用场景
多种算法或行:系统有多种算法或行为可供选择,并且算法都是动态的。
避免条件语句:在系统中有大量的条件语句(if…else…或者switch…case)来选择算法,使用策略模式可以代替这些条件语句,使得代码更加清晰和灵活。
算法经常变化:如果算法经常变化,使用策略模式能够使得新增或修改算法变得更加容易,而不需要修改使用算法的客户端代码
变种与扩展
StatePattern(状态模式):状态模式和策略模式很相似,都是行为型设计模式,都会根据某些条件改变行为。它们的不同点在于,策略模式通常关注算法的选择,而状态模式关注的是对象的状态。
Template MethodPattern(模板方法模式):模板方法模式定义了算法的框架,并将一些步骤延迟到子类中,策略模式则是通过策略接口提供算法的替代方案。
小结
策略模式是为了让客户端能够在运行时选择合适的算法,而不需要修改具体的类,实现了算法的封装和解耦。通过定义统一的策略接口,将不同的算法封装到不同的策略类中,增强了系统的灵活性和可扩展性。
优点
算法封装:策略模式将每个算法封装到独立的策略类中,可以避免使用大量的条件判断,提升代码的可维护性和扩展性
可以动态切换:客户端可以在运行时切换不同的策略,不必在编译时就确定
缺点
增加类的数量:为了实现策略模式,往往需要为每个具体的策略都创建一个类,这可能导致类的数量增加,增加了系统的复杂性
客户端需要知道所有的策略:客户端必须了解所i有的可用的策略,这会导致客户端代码对具体策略的依赖性比较强
2、观察者模式(Observer Pattern)
概述
是一种行为设计模式,定义了对象之间的一种一对多依赖关系。当一个对象的状态发生变化时,所有依赖于它的对象都会自动得到通知并更新。这种模式常用于实现分布式事件处理系统。
结构
观察者模式主要有以下几个组成部分:
Subject(主题/被观察者):
1、主题对象是被观察的对象,它通常是状态变化的源头。
2、主题对象维护一个观察者列表,当状态变化时,会通知所有观察者
Observer(观察者): 1、观察者对象关注主题对象的状态变化,并在状态变化时进行相应的处理
2、观察者接口通常会定义一个update()的方法,当被观察者状态变化时,update()方法会被调用
ConcreteSubject(具体主题/具体被观察者):
1、具体的被观察者,它实现Subject接口,管理观察者列表,并在状态发生变化时,通知所有注册的观察者
ConcreteObserver:(具体观察者):
1、具体的观察者,继承自Observer接口,实现update()方法,处理观察者状态变化时的响应
示例
<?php
<?php
// 观察者接口
interface Observer {
public function update($news);
}
// 主题接口
interface Subject {
public function registerObserver(Observer $observer);
public function removeObserver(Observer $observer);
public function notifyObservers();
}
// 具体的主题类
class NewsAgency implements Subject {
private $observers = [];
private $news;
// 注册观察者
public function registerObserver(Observer $observer) {
$this->observers[] = $observer;
}
// 移除观察者
public function removeObserver(Observer $observer) {
$index = array_search($observer, $this->observers);
if ($index !== false) {
unset($this->observers[$index]);
}
}
// 通知所有观察者
public function notifyObservers() {
foreach ($this->observers as $observer) {
$observer->update($this->news);
}
}
// 设置新闻并通知观察者
public function setNews($news) {
$this->news = $news;
$this->notifyObservers(); // 发布新闻时通知所有观察者
}
}
// 具体的观察者类
class User implements Observer {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function update($news) {
echo $this->name . " 收到新闻更新: " . $news . PHP_EOL;
}
}
// 客户端代码
$newsAgency = new NewsAgency();
// 创建具体的观察者(用户)
$user1 = new User("Alice");
$user2 = new User("Bob");
$user3 = new User("Charlie");
// 注册观察者
$newsAgency->registerObserver($user1);
$newsAgency->registerObserver($user2);
$newsAgency->registerObserver($user3);
// 发布新闻
$newsAgency->setNews("今天的新闻头条:PHP 设计模式");
// 移除观察者
$newsAgency->removeObserver($user2);
// 发布新新闻
$newsAgency->setNews("今天的新闻头条:观察者模式在PHP中的实现");
?>
运行结果
Alice 收到新闻更新: 今天的新闻头条:PHP 设计模式
Bob 收到新闻更新: 今天的新闻头条:PHP 设计模式
Charlie 收到新闻更新: 今天的新闻头条:PHP 设计模式
Alice 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现
Charlie 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现
适用场景
观察者模式适用于以下情况:
事件驱动系统:例如,点击事件、输入框变化事件等。
消息推送系统:如新闻推送、天气更新推送等。
实时数据监控系统:比如股票行情、体育比赛数据的实时更新。
GUI框架:如按钮点击、窗口变化等事件处理。
变种与扩展
推模型与拉模型:
推模型:主题对象将更新的内容主动推送给观察者。例如,主题直接将新闻内容传递给观察者。
拉模型:观察者通过主题对象拉取更新内容。例如,观察者请求最新的新闻内容,而不是由主题主动推送。 发布-订阅模式(Pub-Sub):
发布-订阅模式是一种广泛使用的观察者模式变种,常常结合消息队列或事件总线。它不仅可以将事件通知从发布者传递给订阅者,还支持消息过滤、延迟通知等功能。
小结
观察者模式是一种非常实用的设计模式,适用于需要多个对象响应某个对象状态变化的场景。通过解耦对象之间的关系,它使得系统更加灵活和可扩展。虽然在某些复杂系统中可能会引入性能或管理上的挑战,但其简单和直观的实现方式使得它在很多场合得到了广泛应用。在 PHP 中实现观察者模式相对简单,能够帮助开发者构建高效、灵活的事件驱动系统。
优点
解耦:观察者模式让主题和观察者之间不直接依赖,主题不知道观察者的具体类,观察者也不知道主题的具体内容,二者只通过接口进行交互。这样,系统更加灵活,可扩展性强。
动态更新:观察者模式使得系统能够在运行时动态添加或移除观察者,无需修改主题类或已有的观察者类。
多播通信:一个主题可以同时通知多个观察者,适合于广播式的事件处理(如推送通知、实时消息更新等)。
缺点
可能导致内存泄漏:如果观察者没有及时取消订阅,可能会导致主题无法被垃圾回收,从而造成内存泄漏。
依赖链复杂:在某些复杂系统中,观察者之间可能会互相依赖,从而形成复杂的依赖关系,增加系统的复杂度。
通知开销:如果观察者数量很多,每次通知可能需要遍历所有观察者,影响性能。