前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >php设计模式(二十):状态模式(State)

php设计模式(二十):状态模式(State)

作者头像
Thinker1024
发布2023-09-18 16:09:53
2410
发布2023-09-18 16:09:53
举报
文章被收录于专栏:编程语言的世界

状态模式

状态模式又称为:State。状态是一种行为设计模式,能在一个对象的内部状态变化时改变其行为,使其看上去就像改变了自身所属的类一样。

问题

有一个 文档 Document 类。 文档可能会处于 草稿(Draft) 、 审阅中 (Moderation)和 已发布(Published)三种状态中的一种。

文档的 发布(publish)方法在不同状态下的行为略有不同:

  1. 处于 草稿 状态时,它会将文档转移到审阅中状态。
  2. 处于 审阅中 状态时,如果当前用户是管理员,它会公开发布文档。
  3. 处于 已发布 状态时,可以撤回成 草稿 状态。

平常可能会直接将状态转换的操作写到一个方法中

代码语言:javascript
复制
switch ($status) {
    case 'Draft':
        break;
    case 'Moderation':
        break;
    case 'Published':
        break;
}

PHP

Copy

为了能根据当前状态选择完成相应行为的方法,绝大部分方法中会包含复杂的条件语句。修改其转换逻辑可能会涉及到修改所有方法中的状态条件语句,导致代码的维护工作非常艰难。这个问题会随着项目进行变得越发严重。我们很难在设计阶段预测到所有可能的状态和转换。随着时间推移,最初仅包 含有限条件语句的简洁状态机可能会变成臃肿的一团乱麻。

解决方法

我们将工作委派给一个状态对象。将所有可能状态新建一个类,然后将所有状态的对应行为抽取到这些类中。也就是说我们把具体的转化过程交个具体的状态类,而无需到使用状态的类中编写。

原始对象被称为上下文(context),它并不会自行实现所有行为,而是会保存一个指向表示当前状态的状态对象的引用,且将所有与状态相关的工作委派给该对象。

结构

State:状态基类; Draft : 实现 State 接口的具体状态类; Document:具体的使用状态模式类 ;

代码示例

状态基类

代码语言:javascript
复制
abstract class State
{
    /**
     * 当前类
     * @var Document
     */
    public Document $document;

    public function __construct(Document $document)
    {
        $this->document = $document;
    }

    /**
     * 渲染
     * @return mixed
     * @author chendashengpc
     */
    abstract public function render();

    /**
     * 发布
     * @return mixed
     * @author chendashengpc
     */
    abstract public function publish();
}

PHP

Copy

具体状态类

草稿

代码语言:javascript
复制
/**
 * 草稿
 */
class Draft extends State
{
    public function render()
    {
        return '草稿状态';
    }

    /**
     * 发布为审核中
     * @return mixed|void
     * @author chendashengpc
     */
    public function publish()
    {
        $this->document->changeState(new Moderation($this->document));
    }
}

PHP

Copy

审查中

代码语言:javascript
复制
/**
 * 审查中
 */
class Moderation extends State
{
    public function render()
    {
        return '审查状态';
    }

    /**
     * 发布为审核中
     * @return mixed|void
     * @author chendashengpc
     */
    public function publish()
    {
        $this->document->changeState(new Published($this->document));
    }
}

PHP

Copy

已发表

代码语言:javascript
复制
/**
 * 已发表
 */
class Published extends State
{
    public function render()
    {
        return '已发表状态';
    }

    /**
     * 发布成功了,再次可变为草稿
     * @return mixed|void
     * @author chendashengpc
     */
    public function publish()
    {
        $this->document->changeState(new Draft($this->document));
    }
}

PHP

Copy

用状态模式类

代码语言:javascript
复制
class Document
{
    protected State $state;

    /**
     * 初始化默认状态
     */
    public function __construct()
    {
        $this->state = new Draft($this);
    }

    /**
     * 渲染
     * @return void
     * @author chendashengpc
     */
    public function render()
    {
        return $this->state->render();
    }

    /**
     * 发布
     * @return void
     * @author chendashengpc
     */
    public function publish()
    {
        return $this->state->publish();
    }

    /**
     * 修改状态
     * @param State $state
     * @return void
     * @author chendashengpc
     */
    public function changeState(State $state)
    {
        $this->state = $state;
    }
}

PHP

Copy

客户端使用

代码语言:javascript
复制
$document = new Document();
// 处于草稿阶段
echo $document->render() . PHP_EOL;
// 发布为审核状态
$document->publish();
echo $document->render() . PHP_EOL;
// 发布
$document->publish();
echo $document->render() . PHP_EOL;

PHP

Copy

输出

代码语言:javascript
复制
草稿状态
审查状态
已发表状态

UML

优缺点

优点

  • 单一职责原则。将与特定状态相关的代码放在单独的类中。
  • 开闭原则。无需修改已有状态类和上下文就能引入新状态。
  • 通过消除臃肿的状态机条件语句简化上下文代码。

缺点

  • 如果状态机只有很少的几个状态,或者很少发生改变,那么应用该模式可能会显得小题大作。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 状态模式
  • 问题
  • 解决方法
  • 结构
  • 代码示例
    • 状态基类
      • 具体状态类
        • 用状态模式类
          • 客户端使用
          • UML
          • 优缺点
            • 优点
              • 缺点
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档