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)过于复杂时,可以此模式将状态的判断逻辑 ...
随机推荐
- 【笔记】KNN之分类准确度
分类准确度 分类准确度 以sklearn中的手写数字datasets.load_digits为例,其是8*8的图形,具有64个特征值,类别由0到9 我们挑选出666这个图形,将其可视化 X = dig ...
- iNeuOS工业互网平台,在纸业领域的成功应用案例
目 录 1. 项目背景... 2 2. 项目基本情况... 3 3. 概念解释... 5 1. 项目背景 最终用户是全国第5大纸业集团之一,年浆纸产能40 ...
- epoll水平/边缘触发模式下阻塞/非阻塞EPOLLOUT事件触发条件及次数
在IO多路复用技术中,epoll默认的事件触发模式为Level_triggered(水平触发)模式,即当被监控的文件描述符上有可读/写事件发生时,epoll_wait()会通知处理程序去读写.如果这次 ...
- Sqli-Labs less46-53
less-46 前置基础知识: select * from users order by 1 desc ;使用降序(倒序)排列 select * from users order by 1 asc ; ...
- noip28
东方专场? T1 %%%WYZG 话说我考场上还想二维hash来着 考虑只记录弹幕中x的相对位置. 先选定弹幕一个点作为基准点(第一个出现的x即可),然后,枚举其他的x,记录下坐标差,然后去方格图中枚 ...
- NOIP 模拟 6 考试总结
T1 这道题是一道裸的暴力,考场写挂了 \(5pts\) 原因竟是忘了删注释,难受 题解 T2 这道题是一道启发式合并,没想出来,拿了个暴力分跑了 题解 T3 这道题就是一道数学期望,想出来就水得很, ...
- JavaScript之BOM和DOM及其兼容操作详细总结
BOM(浏览器对象模型) 所有浏览器都支持window对象,他表示浏览器窗口. 所有js全局对象,函数,变量均自动成为window对象的成员. 全局变量是window对象的属性. 全局函数是windo ...
- JSON.stringify()还可以这么用
最近做项目的时候遇到一个对象深拷贝的问题,网上看了下发现最为简便的方法是JSON.stringify(),比如你要深拷贝一个对象,可以这么做: var test={ a:"hello&quo ...
- springboot中@Mapper和@Repository的区别
@Mapper和@Repository是常用的两个注解,两者都是用在dao上,两者功能差不多,容易混淆,有必要清楚其细微区别: 区别: @Repository需要在Spring中配置扫描地址,然后生成 ...
- .net 的析构函数和dispose模式