从0开始学PHP面向对象内容之常用设计模式(策略,观察者)

PHP设计模式------行为型模式

PHP 设计模式中的行为模式(Behavioral Patterns)主要关注对象之间的通信和交互。行为模式的目的是在不暴露对象之间的具体通信细节的情况下,定义对象的行为和职责。它们常用于解决对象如何协调工作的问题,提高系统的灵活性、可扩展性和可维护性。

1、策略模式(Strategy Pattern)

概述

策略模式定义了一系列算法,并将每个算法封装起来,使他们可以互相替换,该模式使得算法可以独立于使用它的客户端变化。也就是说,测策略模式让一个类的行为可以在运行时被改变,从而实现不同的业务逻辑。

结构

策略模式的结构通常包含以下几个组成部分:

1、Context(环境类)

维护一个指向具体策略类的引用。

向客户端暴露一个公共的接口,用于调用具体的策略行为

2、Strategy(策略接口)

定义一个统一的策略接口,通常是一个抽象类或者接口,所有具体策略类都实现这个接口,包含算法的具体实现。

3、ConcreteStrategy(具体策略类):

实现策略接口中的算法

实例

以一个简单的支付系统为例,假设用户可以选择不同的支付方式(如支付宝、微信支付、信用卡支付等),我们可以使用策略模式来实现。

php 复制代码
// 策略接口
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);
    }
}

运行结果

php 复制代码
使用支付宝支付 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

<?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中的实现");

?>

运行结果

php 复制代码
Alice 收到新闻更新: 今天的新闻头条:PHP 设计模式
Bob 收到新闻更新: 今天的新闻头条:PHP 设计模式
Charlie 收到新闻更新: 今天的新闻头条:PHP 设计模式
Alice 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现
Charlie 收到新闻更新: 今天的新闻头条:观察者模式在PHP中的实现

适用场景

观察者模式适用于以下情况:
事件驱动系统 :例如,点击事件、输入框变化事件等。
消息推送系统 :如新闻推送、天气更新推送等。
实时数据监控系统 :比如股票行情、体育比赛数据的实时更新。
GUI框架:如按钮点击、窗口变化等事件处理。

变种与扩展

推模型与拉模型
推模型 :主题对象将更新的内容主动推送给观察者。例如,主题直接将新闻内容传递给观察者。
拉模型 :观察者通过主题对象拉取更新内容。例如,观察者请求最新的新闻内容,而不是由主题主动推送。 发布-订阅模式(Pub-Sub)
发布-订阅模式是一种广泛使用的观察者模式变种,常常结合消息队列或事件总线。它不仅可以将事件通知从发布者传递给订阅者,还支持消息过滤、延迟通知等功能。

小结

观察者模式是一种非常实用的设计模式,适用于需要多个对象响应某个对象状态变化的场景。通过解耦对象之间的关系,它使得系统更加灵活和可扩展。虽然在某些复杂系统中可能会引入性能或管理上的挑战,但其简单和直观的实现方式使得它在很多场合得到了广泛应用。在 PHP 中实现观察者模式相对简单,能够帮助开发者构建高效、灵活的事件驱动系统。

优点

解耦 :观察者模式让主题和观察者之间不直接依赖,主题不知道观察者的具体类,观察者也不知道主题的具体内容,二者只通过接口进行交互。这样,系统更加灵活,可扩展性强。
动态更新 :观察者模式使得系统能够在运行时动态添加或移除观察者,无需修改主题类或已有的观察者类。
多播通信:一个主题可以同时通知多个观察者,适合于广播式的事件处理(如推送通知、实时消息更新等)。

缺点

可能导致内存泄漏 :如果观察者没有及时取消订阅,可能会导致主题无法被垃圾回收,从而造成内存泄漏。
依赖链复杂 :在某些复杂系统中,观察者之间可能会互相依赖,从而形成复杂的依赖关系,增加系统的复杂度。
通知开销:如果观察者数量很多,每次通知可能需要遍历所有观察者,影响性能。

相关推荐
aaasssdddd962 小时前
C++的封装(十四):《设计模式》这本书
数据结构·c++·设计模式
T1an-12 小时前
设计模式之【观察者模式】
观察者模式·设计模式
龙哥·三年风水3 小时前
workman服务端开发模式-应用开发-后端api推送修改二
分布式·gateway·php
计算机徐师兄4 小时前
基于TP5框架的家具购物小程序的设计与实现【附源码、文档】
小程序·php·家具购物小程序·家具购物微信小程序·家具购物
思忖小下4 小时前
梳理你的思路(从OOP到架构设计)_设计模式Factory Method模式
设计模式·工厂方法模式·eit
希雅不是希望5 小时前
Ubuntu命令行网络配置
网络·ubuntu·php
霁月风5 小时前
设计模式——工厂方法模式
c++·设计模式·工厂方法模式
发飙的蜗牛'7 小时前
23种设计模式
android·java·设计模式
龙哥·三年风水7 小时前
workman服务端开发模式-应用开发-后端api推送修改一
分布式·gateway·php
开心工作室_kaic15 小时前
springboot461学生成绩分析和弱项辅助系统设计(论文+源码)_kaic
开发语言·数据库·vue.js·php·apache