设计模式专题(十二)——状态模式

设计模式专题(十二)——状态模式

(原创内容,转载请注明来源,谢谢)

一、概述

状态模式(State)是指当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。状态模式主要解决对象的状态转换表达式过于复杂的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

当状态的变化,会涉及很多的步骤,则用状态模式可以让流程更清晰,并更利于维护。

状态模式的优点,在于将内部的复杂局部状态变化分割出来,将复杂的状态行为分离出去。

状态模式和策略模式相似,是将不同的状态用不同的类进行分开,有一个统一的地方去调用。

但是不同之处在于,状态模式中各个状态是互相联系,且根据业务需要,执行完其中一个状态类后,通常需要执行下一个状态类。另外,状态模式的状态变化到下一个类这件事情,不是由总的类去控制,而是每个不同的状态类会自动根据条件去通知其他状态类。

而策略模式,更注重于依赖注入,由一个总的类去判断状态后,去选择调用不同的类。

状态模式的行为是平行性,不可相互替换的;而策略模式的行为是平等的,是可以相互替换的。

二、类图

三、业务场景

1)业务分析

以购物订单为例,有支付状态、发货状态、退货状态、退款状态等状态,状态之间互相有联系:

1、每种状态的变化都会对其他状态有所限制或允许,按照业务场景,以【支付状态-发货状态/退货状态-退款状态】作为区分,支付状态是前提条件,发货状态和退货状态并行。

2、支付状态有待支付、已支付,待支付时其他状态都为不允许;为已支付时,发货状态分为已发货、未发货、无货;退货状态为没有退货申请、有退货申请。

3、发货状态分为待发货、已发货、确认收货、退货申请,如果是待发货的情况下,收到退货申请,则直接审批通过、退货成功,进入退货状态;如果已发货,则由商家决定允许退货、不允许退货。另外,发货状态还有确认收货的状态,此时不允许退货;而如果已经发退货申请,则不允许确认收货。

4、退货状态分为直接退货(由于未发货)、等待商家审批、允许退货、不允许退货。直接退货和允许退货则影响到退款状态为开始退款,不允许退货则返回支付状态为退款失败,等待审批状态为挂起。退货成功时不允许确认收货。

5、退款状态为开始退款、退款成功两种状态。

2)功能分析

1、客户端的类Shopping,可以支付、退款申请、确认收货。

2、状态基类,支付、退款申请调用支付类,确认收货调用收货类。再由这两个类去调用其它的类进行操作。

3、状态类的子类,包括支付类、发货类、退货类、退款类,共四个类。

3)PHP实现

由于几个子类相似,仅实现支付类和发货类两个子类。

         //订单实体
class Order{
         public $payState;//支付状态
         public$deliveryState;//发货状态
         public $returnState;//退货状态
         public $refundState;//退款状态
}
//客户端类
class Shopping{
         //....先行进行各类操作验证,确认有操作权限后
         private $order;
         private $stateBase;
         public function__construct(Order $order){
                   $this->order= $order;
                   $this->stateBase= new StateBase($order);
         }
         public function pay(){
                   return$this->stateBase->pay();
         }
         public functionrefund(){
                   return$this->stateBase->refund();
         }
         public functionconfirmRecipt(){
                   return$this->stateBase->confirmRecipt();
         }
}
//状态基类
abstract class StateBase{
         private $order;
         public function__construct(Order $order){
                   $this->order= $order;
         }
         public function pay(){
                   return newStatePay($this->order, 'pay');
         }
         public functionrefund(){
                   return newStatePay($this->order, 'refund');
         }
         public functionconfirmRecipt(){
                   return newStatePay($this->order, 'confirm');
         }
}
//支付类
class StatePay extends StateBase{
         private $order;
         public static constNOT_PAY = 0;
         public static constHAS_PAY = 1;
         public function__construct(Order $order, $func){
                   $this->order= $order;
                   if(method_exists($this,$func)){
                            return$this->$func;
                   }else{
                            returnfalse;
                   }
         }
         //支付
         public function pay(){
                   if(self::HAS_PAY== $this->order->payState){
                            echo'已支付,不用重复支付';
                            returnfalse;
                   }
                   $this->order->payState= self::HAS_PAY;
                   return newStateGoods($this->order, 'send');
         }
         //退款后状态置于未支付
         public functionsetNotPay(){
                   $this->order->payState= self::NOT_PAY;
                   return$this->order;
         }
}
//发货类
class StateGoods extends StateBase{
         private $order;
         public static constNOT_SEND = 0;
         public static constHAS_SEND = 1;
         public static constHAS_RECEIVE = 2;
         public static constAPPLY_RETURN = 3;
         public function__construct(Order $order, $func){
                   $this->order= $order;
                   if(method_exists($this,$func)){
                            return$this->$func;
                   }else{
                            returnfalse;
                   }
         }
         //发货
         public functionsend(){
                   if(StatePay::HAS_PAY!= $this->order->payState){
                            echo'请先付款';
                            returnfalse;
                   }
                   if(self::NOT_SEND!= $this->order->payState){
                            echo'不在未发货状态,不能发货';
                            returnfalse;
                   }
         }
}

——written by linhxx 2017.08.09

相关阅读:

设计模式专题(十一)——抽象工厂模式

设计模式专题(十)——观察者模式

设计模式专题(九) ——外观模式

设计模式专题(八) ——模板方法模式

设计模式专题(七)——建造者模式

设计模式专题(六)——原型模式

设计模式专题(五)——工厂方法模式

设计模式专题(四)——代理模式

设计模式专题(三)——装饰模式

设计模式专题(二)——策略模式

设计模式专题(一)——面向对象的设计原则

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-08-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏hbbliyong

C# ini文件读写类

VC中提供了API函数进行INI文件的读写操作,但是微软推出的C#编程语言中却没有相应的方法,下面是一个C# ini文件读写类, 从网上收集的,很全,就是没有对...

2876
来自专栏Albert陈凯

2018-07-10 如何用消息系统避免分布式事务?1 本地事务2 分布式事务—两阶段提交协议3 使用消息队列来避免分布式事务参考文献

前阵子从支付宝转账1万块钱到余额宝,这是日常生活的一件普通小事,但作为互联网研发人员的职业病,我就思考支付宝扣除1万之后,如果系统挂掉怎么办,这时余额宝账户并没...

724
来自专栏Jerry的SAP技术分享

SAP HANA Hint简介

我发现Google和百度上关于HANA DB Hint的中文介绍比较少,所以就写了这一篇。本文部分内容来自SAP note 2142945 – FAQ: SAP...

25610
来自专栏androidBlog

建造者模式(Builder)及其应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/...

351
来自专栏乐百川的学习频道

设计模式(二十四) 访问者模式

访问者模式提供了一种方法,将算法和数据结构分离。假设我们需要对一个数据结构进行不同的操作,就可以考虑使用访问者模式。访问者模式的要点在于,需要一个访问者接口,提...

1956
来自专栏Google Dart

AngularDart4.0 高级-层级依赖注入器 顶

在Dependency Injection指南中你学会了基础的Angular依赖注入. Angular有一个层级依赖注入 系统. 实际上是一个与组件树相平行的...

401
来自专栏静默虚空的博客

[设计模式]建造者模式

简介 建造者模式 (Builder)将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。  建造者模式是一种对象创建型模式 (可参考 设计...

1687
来自专栏分布式系统进阶

一个有限状态机的C++实现

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invi...

834
来自专栏H2Cloud

FFLIb Demo && CQRS

使用FFLIB 构建了一个demo,该demo模拟了一个常见的游戏后台架构,该demo主要有一下亮点: FFLIB 实现进程间通信非常方便 基于CQRS 思想构...

2558
来自专栏Linyb极客之路

并发编程之Semaphore

一、简介 Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。很多年以来,我都觉得从字面上很难理解...

4068

扫描关注云+社区