一、什么是状态模式?
状态模式的定义:
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。 状态模式的优点:
结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。 状态模式的缺点:
状态模式的使用必然会增加系统的类与对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。 状态模式的应用场景:
当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。
二、文件切片上传
文件切片上传是一个比较常见的需求。其主要步骤如下:
读取文件基本信息
将文件按照指定大小切片
创建上传记录,用以标识文件片段
依次、并行上传文件片段(需注意浏览器的最大并行请求数) 另外还涉及到删除、重新上传等功能。 在文件上传的不同阶段,对文件不同操作的处理逻辑是不一样的,会用到大量if-else
语句。 我们先看一段关于删除文件的代码:
Upload.delete = function() { if (/* 创建上传记录中 */) { /* 取消创建上传记录 */ /* 删除本条数据 */ } else if (/* 创建上传记录成功 */) { /* 删除上传记录 */ /* 删除本条数据 */ } else if (/* 创建上传记录失败 */) { /* 删除本条数据 */ } else if (/* 文件上传中 */) { /* 删除上传记录 */ /* 取消上传 */ /* 删除本条数据 */ } else if (/* 文件上传失败 */) { /* 删除上传记录 */ /* 删除本条数据 */ } else if (/* 文件上传成功 */) { /* 删除上传记录 */ /* 删除文件 */ /* 删除本条数据 */ }}
如果后续需求调整,比如新增/*文件暂停上传*/
的场景,需要改写else-if
逻辑,这会使得我们的代码变得越来越庞大,从而变得难以维护和阅读。而且,在实际开发中,需要处理的逻辑肯定比这多得多,因此,重构此类代码是非常有必要的。
三、重构以上代码
1、我们先为文件上传的每个阶段都定义一个状态类:
/* 创建上传记录中 */let CreatingState = function () { }/* 创建上传记录成功 */let CreateSucceedState = function () { }/* 创建上传记录失败 */let CreateFailState = function () { }/* 文件上传中 */let UploadingState = function () { }/* 文件上传成功 */let UploadSucceedState = function () { }/* 文件上传失败 */let UploadErrorState = function () { }
2、分别为每个状态类设置删除方法
/* 创建上传记录中 */CreatingState.prototype.delete = function () { /* 取消创建上传记录 */ /* 删除本条数据 */}/* 创建上传记录成功 */CreatingState.prototype.delete = function () { /* 删除上传记录 */ /* 删除本条数据 */}/* 创建上传记录失败 */CreatingState.prototype.delete = function () { /* 删除本条数据 */}/* 文件上传中 */CreatingState.prototype.delete = function () { /* 删除上传记录 */ /* 取消上传 */ /* 删除本条数据 */}/* 文件上传成功 */CreatingState.prototype.delete = function () { /* 删除上传记录 */ /* 删除本条数据 */}/* 文件上传失败 */CreatingState.prototype.delete = function () { /* 删除上传记录 */ /* 删除文件 */ /* 删除本条数据 */}
3、创建Upload构造函数,为每种状态类创建一个示例对象
let Upload = function () { this.creatingState = new CreatingState(this); this.createSucceedState = new CreateSucceedState(this); this.createFailState = new CreateFailState(this); this.uploadingState = new UploadingState(this); this.uploadSucceedState = new UploadSucceedState(this); this.uploadErrorState = new UploadErrorState(this); this.deleteSucceedState = new DeleteSucceedState(this)}
4、在不同的上传阶段变更Upload的状态,也是为了将事件委托给对应的状态类来执行
/* 创建上传记录中 */this.uploadState = this.creatingState/* 创建上传记录成功 */this.uploadState = this.createSucceedState/* 创建上传记录失败 */this.uploadState = this.createFailState/* 文件上传中 */this.uploadState = this.uploadingState/* 文件上传成功 */this.uploadState = this.uploadSucceedState/* 文件上传失败 */this.uploadState = this.uploadErrorState/* 将删除事件委托给当前状态类 */Upload.prototype.delete = function () { this.uploadState.delete()}
5、使用
let uploader = new Upload();/* 删除文件 */uploader.delete()
重构结束。
原文:https://juejin.cn/post/7096410361313624071