一,总体概要
1,笔者浅谈
状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。 看一个例子:
var TrafficLight = function () {
var count = 0;
var currentState = new Red(this); this.change = function (state) {
// limits number of changes
if (count++ >= 10) return;
currentState = state;
currentState.go();
}; this.start = function () {
currentState.go();
};
}
var Red = function (light) {
this.light = light; this.go = function () {
log.add("Red --> for 1 minute");
light.change(new Green(light));
}
};
var Yellow = function (light) {
this.light = light; this.go = function () {
log.add("Yellow --> for 10 seconds");
light.change(new Red(light));
}
};
var Green = function (light) {
this.light = light; this.go = function () {
log.add("Green --> for 1 minute");
light.change(new Yellow(light));
}
};
var log = (function () {
var log = ""; return {
add: function (msg) { log += msg + "\n"; },
show: function () { alert(log); log = ""; }
}
})(); function run() {
var light = new TrafficLight();
light.start(); log.show();
}
在示例代码中分为三种状态:红色,黄色,绿色
我们的例子是一个交通灯(即信号灯对象)有3种不同的状态:红色,黄色和绿色,各有自己的一套规则。规则是这样的:交通灯是红色的。延迟红状态变为绿色状态后。然后,一段时间后,绿色的状态更改为黄色的状态。
一个非常短暂的延迟黄色状态变为红色后,等等。
需要注意的是,它是对象状态决定下一个状态过渡的重要。这也是对象状态变化,交通灯的当前状态------没有交通灯本身。
出于演示的目的,一个内置的计数器记录状态发生变化的数量,否则程序会运行下去。日志功能是一个帮助它收集并显示结果。
二,源码案例参考
采用让状态对象来维护和转换状态的调用顺序
1)调用上下文的方法来处理业务请求。
2)获取State对象。
3)委托让相应的状态对象去处理。
4)调用方法得到下一个状态方法。
5)设置下一个状态方法。
6)再到5),直到结束。
三,案例引入
再次强调一下状态模式的意图
Context: 环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个具体处理当前状态的实例对象。
State:状态接口,用来封装与上下文的一个特定状态所对应的行为。
ConcreteState: 具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。
例子场景:
模拟工作流中的请假流程,流程是这样的:
当某人提出请假申请,先由项目经理审批,
如果项目经理不同意,审批就直接结束;
如果项目经理同意了,再看请假的天数是否超过3天,项目经理的审批权限只有3天以内,
如果请假天数在3天以内,那么审批也直接结束,
否则就提交给部门经理,部门经理审核过后,无论是否同意,审批都直接结束。
(function () {
// 模拟工作流 // 定义请假单的业务数据模型
function LeaveRequestModel() {
// 请假人
this.user = '';
// 请假开始时间
this.beginDate = '';
// 请假天数
this.leaveDays = '';
// 审核结果
this.result = '';
} /*
请假流程,需项目经理和部门经理审批
*/ function LeaveRequestContext2() {
this.state = null;
// 包含流程处理需要的业务数据对象
this.businessVO = null;
this.doWork = function () {
if (typeof this.state == 'function') {
this.state = this.state(this);
this.doWork();
}
};
} function projectManagerState(request) {
var leaveRequestModel = request.businessVO; console.log('项目经理审核中,请稍候。。');
console.log(leaveRequestModel.user + '申请从'
+ leaveRequestModel.beginDate + '开始请假'
+ leaveRequestModel.leaveDays + '天,请项目经理审核(1为同意,2为不同意)'); var answer = window.prompt('1为同意,2为不同意');
var result = answer == 1 ? '同意' : '不同意';
leaveRequestModel.result = '项目经理审核结果:' + result; var state;
if (answer == 1) {
if (leaveRequestModel.leaveDays > 3) {
state = depManagerState;
} else {
state = auditOverState;
}
} else {
state = auditOverState;
} return state;
} function depManagerState(request) {
var leaveRequestModel = request.businessVO; console.log('部门经理审核中,请稍候。。');
console.log(leaveRequestModel.user + '申请从'
+ leaveRequestModel.beginDate + '开始请假'
+ leaveRequestModel.leaveDays + '天,请项目经理审核(1为同意,2为不同意)'); var answer = window.prompt('1为同意,2为不同意');
var result = answer == 1 ? '同意' : '不同意';
leaveRequestModel.result = '部门经理审核结果:' + result; return auditOverState;
} function auditOverState(request) {
var leaveRequestModel = request.businessVO;
// do sth
console.log(leaveRequestModel.user + ',你的请假申请已经审核结束,结果是:' + leaveRequestModel.result);
} var lrm = new LeaveRequestModel();
lrm.user = '小林';
lrm.beginDate = '2014-4-2';
lrm.leaveDays = 5; var request = new LeaveRequestContext2();
request.businessVO = lrm;
request.state = projectManagerState; request.doWork(); }());
四,总结一下
认识状态模式
使用场景
State模式在实际使用中比较多,适合"状态的切换"。因为我们经常会使用If else if else 进行状态切换,如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了。
不只是根据状态,也有根据属性。如果某个对象的属性不同,对象的行为就不一样,这点在Database系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,
用以标识记录中一些特殊性质的记录,这种属性的改变(切换)又是随时可能发生的,就有可能要使用State。
状态和行为
所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上。
状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应的不同功能。也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为。
由于状态是在运行期被改变的,因此行为也会在运行期根据状态的改变而改变。
行为的平行性
注意平行线而不是平等性。所谓平行性指的是各个状态的行为所处的层次是一样的,相互独立的、没有关联的,是根据不同的状态来决定到底走平行线的哪一条。
行为是不同的,当然对应的实现也是不同的,相互之间是不可替换的。
环境和状态处理对象
在状态模式中,环境(Context)是持有状态的对象,但是环境(Context)自身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。
在具体的状态处理类中经常需要获取环境(Context)自身的数据,甚至在必要的时候会回调环境(Context)的方法,因此,通常将环境(Context)自身当作一个参数传递给具体的状态处理类。
客户端一般只和环境(Context)交互。客户端可以用状态对象来配置一个环境(Context),一旦配置完毕,就不再需要和状态对象打交道了。客户端通常不负责运行期间状态的维护,也不负责决定后续到底使用哪一个具体的状态处理对象。
哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)
大熊君说说JS与设计模式之------状态模式State的更多相关文章
-
大熊君说说JS与设计模式之------代理模式Proxy
一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一 ...
-
大熊君说说JS与设计模式之------命令模式Command
一,总体概要 1,笔者浅谈 日常生活中,我们在看电视的时候,通过遥控器选择我们喜欢的频道时,此时我们就是客户端的角色,遥控器的按钮相当于客户请求,而具体执行的对象就是命令对象, 命令模式把一个请求或者 ...
-
大熊君说说JS与设计模式之------策略模式Strategy
一,总体概要 1,笔者浅谈 策略模式,又叫算法簇模式,就是定义了不同的算法,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 策略模式和工厂模式有一定的类似,策略模式相对简单容易理解,并 ...
-
【转】设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
-
设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
-
乐在其中设计模式(C#) - 状态模式(State Pattern)
原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...
-
北风设计模式课程---状态模式State(对象行为型)
北风设计模式课程---状态模式State(对象行为型) 一.总结 一句话总结: 状态模式 具体状态的行为在具体的状态类中就解决,不用交给外部做判断.实质是将多条件判断弄成了多个类,在不同的类中做判断 ...
-
设计模式2——状态模式State
参考链接: 设计模式之状态模式:https://www.cnblogs.com/haoerlv/p/7777789.html 设计模式系列之状态模式:https://www.jianshu.com/p ...
-
二十四种设计模式:状态模式(State Pattern)
状态模式(State Pattern) 介绍允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例有一个Message实体类,对它的操作有Insert()和Get()方法, ...
随机推荐
-
div box container随主体内容自动扩展适应的实现
/**顶部部分*/ .con-tl{ background:url(../images/left.png) no-repeat 0 0 rgba(0, 0, 0, 0); padding-left: ...
-
重新想象 Windows 8.1 Store Apps (75) - 新增控件: Hub, Hyperlink
[源码下载] 重新想象 Windows 8.1 Store Apps (75) - 新增控件: Hub, Hyperlink 作者:webabcd 介绍重新想象 Windows 8.1 Store A ...
-
Linux常用解压文件
tar.gz tar -zxvf filename.tar.gz tar.bz2 tar -vxjf filename.tar.bz2
-
jQuery.mobile.changePage() | jQuery Mobile API Documentation
jQuery.mobile.changePage() | jQuery Mobile API Documentation <script> $.mobile.changePage( &qu ...
-
CI 数据库使用积累
CI 数据库使用积累 一. or_like使用 情景:WMS库存列表过滤器通过产品名称或者SKU查询. 通常此情况采用CI框架提供的or_like语句,如 $this->db-> ...
-
vue子父组件通信
之前在用vue写子父组件通信的时候,老是遇到问题!!! 子组件传值给父组件: 子组件:通过emit方法给父组件传值,这里的upparent是父组件要定义的方法 模板: <div v-on:cli ...
-
Xcode - 打开工程,提示No Scheme解决
错误提示,如图: 解决思路:
-
《LeetBook》leetcode题解(16):3Sum Closest [M]
我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...
-
swift - UIScrollView 的使用
本节详细介绍scrollview的用法 ———————————————————————————————————— UIScrollView 是一个能够滚动的视图控件,可以用来展示大量的内容,并且可以通 ...
-
桥接,NAT,Host Only的区别
桥接,NAT,Host Only的区别 一.Brigde——桥接 :默认使用VMnet0fish批注:只要在虚拟机中将IP设对,即使宿主机的IP是错的,也可以通信.但是如此物理网卡被禁用了,则不能 ...