PHP设计模式之状态模式
状态模式从字面上其实并不是很好理解。这里的状态是什么意思呢?保存状态?那不就是备忘录模式了。其实,这里的状态是类的状态,通过改变类的某个状态,让这个类感觉像是换了一个类一样。说起来有点拗口吧,先学习概念之后再看。
Gof类图及解释
GoF定义:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类
GoF类图

代码实现
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()对象来实现开关状态的切换。
- 看出门道了嘛?这里把状态的变化给封装到外部的实现类去了,并不是这个上下文或者目标类内部来进行状态的切换了
- 那么状态模式的意义呢?这个默认类图的例子过于简单,其实状态模式的真正目的是为了解决复杂的if嵌套问题的,把复杂的if嵌套条件放到一个个的外部状态类中去判断,在后面的实例中我们会看到
- 适用于:一个对象的行为取决于它的状态,并且它的必须在运行时刻根据状态改变自己的行为;一个操作中含有大量的多分支条件语句,且这些分支依赖于该对象的状态;
- 状态模式的特点是:它将与特定状态相关的行为局部化;它使得状态转换显式化;State对象可以被共享;
- 常见于订单系统、会员系统、OA系统中,也就是流程中会出现各种状态变化的情况,都可以使用状态模式来进行整体的设计与架构
我们的手机系统内定制了自己的商城系统,可以在手机上方便的下单购买我们的商品。一个订单(Context)会有多种状态(State),比如未支付、已支付、订单完成、订单退款等等一大堆状态。我们把这些状态都放在了对应的状态类里去实现,不同的状态类都会再去调用该状态下一步的动作,比如已支付后就等待收货、退款后就等待买家填写物流单号等,这样,状态模式就在我们的商城中被灵活的运用起来咯!!
完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/22.state/source/state.php
实例
通常的商城应用中都会有会员体系的存在,一般等级越高的会员可以享受的折扣也会越多,这个时候,运用状态模式就能很轻松的获得会员的等级折扣。当然,最主要的是,使用状态模式可以在需要添加或者删除会员等级时只添加对应的会员折扣状态子类就可以了。其他业务代码都不需要变动,我们一起来看看具体实现吧!
会员折扣图

完整源码: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对象本身的状态(会员分)时,状态模式就是最佳的选择了,也就是上面所说的一个对象的行为取决于它的状态
下期看点
状态模式其实运用的范围很广,但使用的人确不多。毕竟if...else...更加的直观,而且大部分日常应用中的状态一般也很少会去修改或添加。如果你的订单状态需要经常的修改或添加,那肯定在架构设计中存在着问题。但是,通过这个模式的学习,我们看到了面向对象在处理这种问题时所展现的威力,这才是我们对设计模式学习的最终目的,灵活合适地运用,更深入的了解面向对象。好了,最后一个设计模式就要登场了,它就是访问者模式。
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP设计模式之状态模式的更多相关文章
- 【转】设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
- 设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
- 乐在其中设计模式(C#) - 状态模式(State Pattern)
原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...
- 折腾Java设计模式之状态模式
原文地址 折腾Java设计模式之状态模式 状态模式 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.这种类型的设计模式属于行为型模式.在状态模式中,我们创建表示各种状态的对象 ...
- 北风设计模式课程---状态模式State(对象行为型)
北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...
- js设计模式——5.状态模式
js设计模式——5.状态模式 代码演示 /*js设计模式——状态模式*/ // 状态(红灯,黄灯,绿灯) class State { constructor(color) { this.color = ...
- 设计模式2——状态模式State
参考链接: 设计模式之状态模式:https://www.cnblogs.com/haoerlv/p/7777789.html 设计模式系列之状态模式:https://www.jianshu.com/p ...
- python设计模式之状态模式
python设计模式之状态模式 面向对象编程着力于在对象交互时改变它们的状态.在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具.首先,什么是状态 ...
- Head First 设计模式 --10 状态模式
状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了他的类. 用到的设计原则1.封装变化2.多用组合,少用继承3.针对接口编程,不针对实现编程4.松耦合5.对扩展开放,对修改关闭6.依 ...
- 设计模式之 -- 状态模式(State)
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类.当控制一个对象的状态转换条件分支语句(if...else或switch...case)过于复杂时,可以此模式将状态的判断逻辑 ...
随机推荐
- Configure Hosts with Puppet
According to "Pro Puppet" 2nd edition, Chapter 2, "Creating a Module to Manage SSH&qu ...
- 【笔记】衡量线性回归法的指标 MSE,RMS,MAE以及评价回归算法 R Square
衡量线性回归法的指标 MSE,RMS,MAE以及评价回归算法 R Square 衡量线性回归法的指标 对于分类问题来说,我们将原始数据分成了训练数据集和测试数据集两部分,我们使用训练数据集得到模型以后 ...
- Dll文件的创建与测试C#
创建Dll文件 首先使用VS 2019创建Dll项目,创建项目时选择"类库",如下图 在项目中创建类文件,添加测试代码: namespace PlantSim_C_Interfac ...
- DVWA-全等级命令行注入
DVWA简介 DVWA(Damn Vulnerable Web Application)是一个用来进行安全脆弱性鉴定的PHP/MySQL Web应用,旨在为安全专业人员测试自己的专业技能和工具提供合法 ...
- 从net到java:MyBatis快速入门
第一:这不是net与java的对比,只是我学习java相关知识梳理的笔记. 第二:这也没有否认net,只是现在的工作需要自己会java. 第三:这不深入.只是我看了些官网和网上的视频,算是入门的总结. ...
- Git在IDEA中的日常使用
1.Git介绍Git对于做开发的小伙伴并不陌生,Git是现在比较流行的版本控制工具.Git的仓库分为本地仓库和远程仓库,当代码开发完成后,先提交(commit)到本地仓库,再推送(push)到远程仓库 ...
- java简体(繁体)转换器
<!--中文字符简繁体互相转换--> <dependency> <groupId>com.github.nobodxbodon</groupId> &l ...
- 详解 OpenGL ES 2.x 渲染流程
khronos官方对OpenGL ES的描述如下: OpenGL ES is a royalty-free, cross-platform API for rendering advanced 2D ...
- 2018秋招C/C++面试题总结
一.C和C++的区别是什么? C是面向过程的语言,C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛.C中函数不能进行重载,C++函数可以重载C++在C的基础上增添类,C是一个结构化语言,它 ...
- CPU 进程 线程 关系与区别