讲师中心 微信公众号
AI工具推荐 视频效率加速

PHP中什么是状态模式?通过实例来了解它

夏静小哥_8369

夏静小哥_8369

发布时间:2021-07-27 18:33:36

|

2542人浏览过

|

来源于掘金--硬核项目经理

转载

在之前的文章《一起聊聊php中的单例模式》中我们介绍了php中的单例模式,下面本篇文章带大家了解一下php设计模式中的状态模式

PHP中什么是状态模式?通过实例来了解它

状态模式从字面上其实并不是很好理解。这里的状态是什么意思呢?保存状态?那不就是备忘录模式了。其实,这里的状态是类的状态,通过改变类的某个状态,让这个类感觉像是换了一个类一样。说起来有点拗口吧,先学习概念之后再看。

Gof类图及解释

GoF定义:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类

GoF类图

立即学习PHP免费学习笔记(深入)”;

1.png

代码实现

class Context
{
    private $state;
    public function SetState(State $state): void
    {
        $this->state = $state;
    }
    public function Request(): void
    {
        $this->state = $this->state->Handle();
    }
}

一个上下文类,也可以看作是目标类,它的内部有一个状态对象。当调用Request()的时候,去调用状态类的Handle()方法。目的是当前上下文类状态的变化都由外部的这个状态类来进行操纵。

interface State
{
    public function Handle(): State;
}

class ConcreteStateA implements State
{
    public function Handle(): State
    {
        echo '当前是A状态', PHP_EOL;
        return new ConcreteStateB();
    }
}

class ConcreteStateB implements State
{
    public function Handle(): State
    {
        echo '当前是B状态', PHP_EOL;
        return new ConcreteStateA();
    }
}

抽象状态接口及两个具体实现。这两个具体实现实际上是在相互调用。实现的效果就是上下文类每调用一次Request()方法,内部的状态类就变成别一个状态。就像一个开关,在打开与关闭中来回切换一样。

$c = new Context();
$stateA = new ConcreteStateA();
$c->SetState($stateA);
$c->Request();
$c->Request();
$c->Request();
$c->Request();

客户端的实现,实例化上下文对象并设置初始的状态,然后通过不停的调用Request()对象来实现开关状态的切换。

PHP
PHP

编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。

下载
  • 看出门道了嘛?这里把状态的变化给封装到外部的实现类去了,并不是这个上下文或者目标类内部来进行状态的切换了
  • 那么状态模式的意义呢?这个默认类图的例子过于简单,其实状态模式的真正目的是为了解决复杂的if嵌套问题的,把复杂的if嵌套条件放到一个个的外部状态类中去判断,在后面的实例中我们会看到
  • 适用于:一个对象的行为取决于它的状态,并且它的必须在运行时刻根据状态改变自己的行为;一个操作中含有大量的多分支条件语句,且这些分支依赖于该对象的状态;
  • 状态模式的特点是:它将与特定状态相关的行为局部化;它使得状态转换显式化;State对象可以被共享;
  • 常见于订单系统、会员系统、OA系统中,也就是流程中会出现各种状态变化的情况,都可以使用状态模式来进行整体的设计与架构

我们的手机系统内定制了自己的商城系统,可以在手机上方便的下单购买我们的商品。一个订单(Context)会有多种状态(State),比如未支付、已支付、订单完成、订单退款等等一大堆状态。我们把这些状态都放在了对应的状态类里去实现,不同的状态类都会再去调用该状态下一步的动作,比如已支付后就等待收货、退款后就等待买家填写物流单号等,这样,状态模式就在我们的商城中被灵活的运用起来咯!!

完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/22.state/source/state.php

实例

通常的商城应用中都会有会员体系的存在,一般等级越高的会员可以享受的折扣也会越多,这个时候,运用状态模式就能很轻松的获得会员的等级折扣。当然,最主要的是,使用状态模式可以在需要添加或者删除会员等级时只添加对应的会员折扣状态子类就可以了。其他业务代码都不需要变动,我们一起来看看具体实现吧!

会员折扣图

2.png

完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/22.state/source/state-member.php

<?php

class Member
{
    private $state;
    private $score;

    public function SetState($state)
    {
        $this->state = $state;
    }

    public function SetScore($score)
    {
        $this->score = $score;
    }

    public function GetScore()
    {
        return $this->score;
    }

    public function discount()
    {
        return $this->state->discount($this);
    }
}

interface State
{
    public function discount($member);
}

class PlatinumMemeberState implements State
{
    public function discount($member)
    {
        if ($member->GetScore() >= 1000) {
            return 0.80;
        } else {
            $member->SetState(new GoldMemberState());
            return $member->discount();
        }
    }
}

class GoldMemberState implements State
{
    public function discount($member)
    {
        if ($member->GetScore() >= 800) {
            return 0.85;
        } else {
            $member->SetState(new SilverMemberState());
            return $member->discount();
        }
    }
}

class SilverMemberState implements State
{
    public function discount($member)
    {
        if ($member->GetScore() >= 500) {
            return 0.90;
        } else {
            $member->SetState(new GeneralMemberState());
            return $member->discount();
        }
    }
}

class GeneralMemberState implements State
{
    public function discount($member)
    {
        return 0.95;
    }
}

$m = new Member();
$m->SetState(new PlatinumMemeberState());

$m->SetScore(1200);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;

$m->SetScore(990);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;

$m->SetScore(660);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;

$m->SetScore(10);
echo '当前会员' . $m->GetScore() . '积分,折扣为:' . $m->discount(), PHP_EOL;

说明

  • 如果不使用状态模式,在Member的discount()方法中,我们可能需要写很多层if...else...判断条件
  • 同时,这也带来了方法体会越来越长,越来越难以维护的问题
  • 状态模式正是为了解决这个问题而存在的
  • 当discount()行为的结果依赖于Member对象本身的状态(会员分)时,状态模式就是最佳的选择了,也就是上面所说的一个对象的行为取决于它的状态

原文地址:https://juejin.cn/post/6844903991562731534

作者:硬核项目经理

推荐学习:《PHP视频教程

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
LibLibAI
LibLibAI Hot

一款AI视频创作工具,主要用于国内领先的AI创意平台,以海量模型、低门槛操作与“创作-分享-商业化”生态,让小白与专业创作者都能高效实现图文乃至视频创意表达,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

相关专题

更多
Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

0

2026.09.23

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

0

2026.09.23

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

0

2026.09.23

Conan创建软件包配方指南
Conan创建软件包配方指南

本专题介绍通过conanfile.py创建软件包的方法,讲解包名、版本、依赖和构建设置等基础信息,以及source、build、package、package_info等常用方法的作用及编写思路。

0

2026.09.22

Conan二进制包配置指南
Conan二进制包配置指南

本专题介绍Conan根据操作系统、编译器、架构和构建类型生成二进制包的方法,讲解Profile、Settings、Options及Package ID的作用,帮助管理不同平台和编译环境下的包版本。

0

2026.09.22

Conan私有仓库搭建教程
Conan私有仓库搭建教程

本专题系统的讲解Conan私有仓库的搭建流程,涵盖仓库服务部署、存储目录配置、用户认证、权限划分和远程地址添加,并介绍内部C++依赖包的上传、下载及版本维护方法。

0

2026.09.22

loomy官网入口地址合集
loomy官网入口地址合集

本专题汇总了 Loomy 桌面 AI 助理的官方入口地址合集及使用指南。提供 macOS 与 Windows 客户端下载 。Loomy 是讯飞推出的桌面级 AI 工作搭子,支持文件整理、数据分析、网页操作及通过飞书/钉钉远程操控电脑,助你高效完成本地办公任务 。

0

2026.09.22

NumPy常见函数使用方法
NumPy常见函数使用方法

本专题整理 NumPy 常见函数使用方法相关教程,覆盖函数大全、参数用法、数组运算、统计聚合、排序处理、where 条件筛选、linspace 创建数列等常用场景,帮助读者快速掌握 NumPy 函数调用思路和实际数据处理技巧。

0

2026.09.22

NumPy性能优化版本更新与常见报错排查
NumPy性能优化版本更新与常见报错排查

本专题整理 NumPy 性能优化、版本更新与常见报错排查相关教程,覆盖向量化计算、广播性能、内存布局、NumPy 2.0 升级、版本兼容冲突、安装导入报错、dtype 溢出、矩阵运算异常和 broadcasting 报错修复,帮助读者系统掌握 NumPy 性能调优与问题定位方法。

20

2026.09.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn