状态是什么
状态就是程序运行时的某种可能情况,根据状态的不同,程序的运行结果也不同。比如我们不会向一个少年推荐拐杖,也不会向一个老年人推荐奶瓶一样,不同状态,对应的处理逻辑都不同,这也使得我们程序有各种复杂的判断条件、逻辑分支。每个分支都是一种状态。
状态与程序复杂度
Controller的功能就是根据当前的运行状态,执行一系列的逻辑,并在View层根据当前状态来显示一些信息,并且会把执行对数据模型的影响同步到Model。
状态的粒度影响着我们程序逻辑的复杂度,比如我们把人生阶段分为少年,青年,中年,老年等阶段,还是细化成10岁、20岁、30岁等,处理逻辑的复杂度是不一样的。
程序的逻辑的执行就伴随着程序状态的变化,也就是上下文的变化,有一些需要上下文的逻辑,需要我们去记录状态,根据状态的不同,来执行不同的逻辑。有时候我们写一段新的逻辑的时候发现缺失了某个状态,这时候需要在前面补加上这个状态,并且处理每次用户行为和处理逻辑对状态的变更。这个过程是很常见的,就像view和model的绑定一样常见,自然就有了一些封装,比如状态机,全面的记录每一次状态的变更。如果程序逻辑特别复杂,那么一个状态机是必要的,但如果程序逻辑简单,自己记录一些状态也无可厚非。
状态的前后端划分
有些状态是前端可以自己记录的,比如用户交互的行为,比如时间的变化引起的状态的改变,这些前端都可以自己来维护。但是有一些状态比如多人协作时候的状态,光靠客户端是没法获取的,必须依靠服务端记录状态,然后或者tcp推送或者客户端http拉取的方式,来同步状态。像一些联网游戏,都会有两个状态机,客户端一个,服务端一个。
状态在哪一端维护与我们的前后职能的划分有很大的关系,比如课堂的下课状态,这个状态前端是可以维护的,当然后端也可以计算得出,前端有的逻辑需要这个状态的值,那么可以本地维护也可以远程拉取。区别是放在前端会增加前端计算量和代码复杂度,但是能减少请求。放在后端会增加后端请求数和代码复杂度,但是却能简化前端代码。
状态放在前端维护还是后端维护有一个原则,首先涉及到多人协作的,状态肯定会放在后端维护,有些甚至会记录到数据库,比如oa等工作流、审批流转的系统、比如订单状态、物流状态等。不涉及到多人的以及不需要记录的状态前端维护就可以了,当然如果有一些状态前端计算特复杂或者需要结合很多接口,那么可以移到后端。状态维护的位置是由是否涉及多人、状态所依赖状态的获取难度、计算复杂度等来综合权衡的。
状态与响应式
前端很多应用都是响应式的,也就是监听状态的变化,状态改变会去联动视图的一系列变更。比如vuex,vue,rxjs等等,mvc各个层次的响应式。响应式的响应机制就是建立在状态改变的基础上的,改变状态或者说触发响应的条件就是用户交互、时间改变、服务端推送的状态等等各种外界的交互。
项目的状态有框架、应用、业务逻辑几个层面,不同层面的状态变化,都可以通过响应式的联动或者命令式的处理,但不是所有的状态都要做成响应式的,有的状态的处理可以用命令式的处理不如:
if(status === 'A') {
} else if (status === 'B') {
} else {
}
也可以响应式的处理如:
this.on('A', () => {})
this.on('B', () => {})
状态有很多,有一些使用响应式来处理式很方便的。使用的原则是响应方向要单一,以及不要用在业务层状态变化的处理,如图:
单向的状态变化,可以通过事件来响应式的处理,但是不应该有很多不同方向的事件监听。同时业务层代码尽量不要用事件,用命令式的回调、promise就可以了。
总之,状态的处理使用命令式还是响应式至少要考虑方向和层次两个方面。
状态与函数式、面向对象
对于状态的封装,函数式和面向对象有不同的思路。
面向对象认为状态是对象所有的,应该封装到对象内部,方法的执行逻辑依赖状态。而函数式则认为状态是导致代码难以服用的罪魁祸首,他们会把状态放到函数之外来维护,某个处理逻辑需要的状态只要通过参数传入就好了,状态和函数是分离开的。
函数式就是把内部状态以及引起内部状态变化的外部副作用和逻辑分离开来,使得函数是可复用,可推导的,像数学公式一样。函数式分离内部状态和外部副作用的思路不同,内部状态式通过分离到函数之外,而副作用是通过进行更高一层的封装来隔离。
总结
程序设计的时候除了需要考虑静态的数据模型之外,也要考虑运行时的状态。
程序的复杂度与状态的粒度
直接相关,按照对状态的不同封装方式
,程序可以是面向对象的或者函数式的,当然也有的混合了两者。状态的维护
放在前端还是后端,以及状态变动的处理
是通过响应式还是命令式都是需要取权衡的。
网友评论