<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>State Pattern</title>
</head>
<body> <script>
/**
* 状态模式
*
* 定义:
* 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
*
* 本质:
* 根据状态来分离和选择行为
*
* 1.状态和行为
* 所谓对象的状态,通常指的就是对象实例的属性的值;而行为指的就是对象的功能,再具体点,行为大多可以对应到方法上。
* 状态模式的功能就是分离状态和行为,通过维护状态的变化,来调用不同状态的的不同功能。
* 也就是说,状态和行为是相关联的,它们的关系可以描述为:状态决定行为。
*
* 2.行为的平行性
* 平行性指的是各个状态的行为所处的层次是一样的,相互是独立的,没有关联的,是根据不同的状态来决定到底走平行线哪一条。行为是不用的,当然对应的实现也是不同的,相互之间是不可替换的。
* 平等性强调的是可替换性,大家是同一行为的不同描述或实现,因此在同一个行为发生的时候,可以根据条件挑选任意的一个实现来进行相应的处理。
* 状态模式和策略模式的结构完全一样。状态模式的行为是平行性的,不可相互替换的;而策略模式的行为是平等性的,可相互替换的。
*
* 3.上下文和状态处理对象呢
* 在状态模式中,上下文是持有状态的对象,但是上下文自身并不处理跟状态相关的行为,而是把处理状态的功能委托给了状态对应的状态处理类来处理。
* 在具体的状态处理类中经常需要获取上下文自身的数据,甚至在必要的时候会回调上下文的方法,因此,通常将上下文自身当作一个参数传递给具体的状态处理类。
* 客户端一般只和上下文交互。客户端可以用状态对象来配置一个上下文,一旦配置完毕,就不需要再和状态对象打交道了。
*
* 4.不完美的OCP体验
* 由于状态的维护和转换在状态模式结构里面,不管你是扩展了状态实现类,还是新添加了状态实现类,都需要修改状态维护和转换的地方。
*
* 5.创建和销毁状态对象
* 究竟何时创建和销毁状态对象?
* 1)当需要使用状态对象的时候创建,使用完后销毁它们
* 2)提前创建它们并始终不销毁。
* 3)采用延迟加载和缓存合用的方式,就是当第一次需要使用状态对象的时候创建,使用完后并不销毁对象,而是把这个对象缓存起来,等待下一次使用,而且在合适的时候,会有缓存框剪销毁状态对象。
* 如果状态在运行时是不可知的,而且上下文比较稳定,建议选择1.
* 如果状态改变很频繁,而且状态对象还存储着大量的数据信息,建议选择2.
* 如果无法确定状态改变是否频繁,而且有些状态对象的状态数据量大,有些较小,建议选择3.
*
* 6.状态模式的调用顺序
* 在Context中进行状态的维护和转换:
* 1)调用上下文的方法来处理业务请求。
* 2)判断并维护状态。
* 3)根据状态来调用相应的状态处理对象的方法。
*
* 采用让状态对象来维护和转换状态的调用顺序
* 1)调用上下文的方法来处理业务请求。
* 2)获取State对象。
* 3)委托让相应的状态对象去处理。
* 4)调用构造方法得到下一个状态对象的实例。
* 5)设置下一个状态处理对象。
* 6)再到6),直到结束。
*
* 状态的维护和转换控制
* 所谓状态的维护,指的是维护状态的数据,给状态设置不用的状态值;而状态的转换,指的是根据状态的变化来选择不用的状态处理对象。在状态模式中,通常有两个地方可以进行状态的维护和转换控制。
* 一个就是在上下文中。因为状态本身通常被实现为上下文对象的状态,因此可以在上下文中进行状态维护,当然也就可以控制状态的转换了。
* 另外一个地方就是在状态的处理类中。当每个状态处理对象处理完自身状态所对应的功能后,可以根据需要指定后继状态,以便让应用能正确处理后继的请求。
*
* 如何选择这两种方式?
* 1.如果状态转换的规则是一定的,一般不需要进行什么扩展规则,那么就适合在上下文中统一进行状态的维护。
* 2.如果状态的转换取决于前一个状态动态处理的结果,或者是依赖于外部数据,为了增强灵活性,这种情况下,一般是在状态处理类中进行状态的维护。
*
* 还可以使用数据库来维护状态
*
*/ (function () {
// 示例代码 // 实现一个与Context的一个特定状态相关的行为
function ConcreteStateA() {} ConcreteStateA.prototype.handle = function () {}; function ConcreteStateB() {} ConcreteStateB.prototype.handle = function () {}; // 定义客户感兴趣的接口,通常会维护一个State的对象实例
function Context(state) {
this.state = state;
} Context.prototype = {
request: function (param) {
this.state.handle(param);
}
};
}()); (function () {
// 示例 function NormalVoteState() {} NormalVoteState.prototype.vote = function (user, voteItem, voteManager) {
voteManager.mapVote[user] = voteItem;
}; function RepeatVoteState() {} RepeatVoteState.prototype.vote = function (user, voteItem, voteManager) {
console.log('请不要重复投票');
}; function SpliteVoteState() {} SpliteVoteState.prototype.vote = function (user, coteItem, voteManager) {
var s = voteManager.mapVote[user];
if (s) {
delete voteManager.mapVote[user];
} console.log('你有恶意刷票行为,取消投票资格');
}; function BlackVoteState() {} BlackVoteState.prototype.vote = function (user, voteItem, voteManager) {
console.log('进入黑名单,将禁止登录和使用本系统');
}; function VoteManager() {
this.state = null;
this.mapVote = {};
this.mapVoteCount = {};
} VoteManager.prototype = {
vote: function (user, voteItem) {
var oldVoteCount = this.mapVoteCount[user] || 0; this.mapVoteCount[user] = ++oldVoteCount; if (oldVoteCount == 1) {
this.state = new NormalVoteState();
} else if (oldVoteCount > 1 && oldVoteCount < 5) {
this.state = new RepeatVoteState();
} else if (oldVoteCount >= 5 && oldVoteCount < 8) {
this.state = new SpliteVoteState();
} else if (oldVoteCount >= 8) {
this.state = new BlackVoteState();
} this.state.vote(user, voteItem, this);
}
}; var vm = new VoteManager();
for (var i = 0; i < 8; i++) {
vm.vote('u1', 'A');
} // another
var States = {
normal: function (user, voteItem, voteManager) {
voteManager.mapVote[user] = voteItem;
},
repeat: function (user, voteItem, voteManager) {
console.log('请不要重复投票');
},
splite: function (user, coteItem, voteManager) {
var s = voteManager.mapVote[user];
if (s != null) {
delete voteManager.mapVote[user];
} console.log('你有恶意刷票行为,取消投票资格');
},
black: function (user, voteItem, voteManager) {
console.log('进入黑名单,将禁止登录和使用本系统');
}
}; function VoteManager2() {
this.state = null;
this.mapVote = {};
this.mapVoteCount = {};
} VoteManager2.prototype = {
vote: function (user, voteItem) {
var oldVoteCount = this.mapVoteCount[user] || 0; this.mapVoteCount[user] = ++oldVoteCount; var state;
if (oldVoteCount == 1) {
state = 'normal';
} else if (oldVoteCount > 1 && oldVoteCount < 5) {
state = 'repeat';
} else if (oldVoteCount >= 5 && oldVoteCount < 8) {
state = 'splite';
} else if (oldVoteCount >= 8) {
state = 'black';
} this.state = States[state]; this.state(user, voteItem, this);
}
}; var vm = new VoteManager2();
for (var i = 0; i < 8; i++) {
vm.vote('u1', 'A');
}
}()); (function () {
// 在状态处理类中进行后继状态的维护和转换 function NormalVoteState() {
this.vote = function (user, voteItem, voteManager) {
voteManager.mapVote[user] = voteItem;
console.log('恭喜你投票成功');
// 正常投票完毕,维护下一个状态,同一个人再投票就重复了
voteManager.mapState[user] = new RepeatVoteState();
};
} function RepeatVoteState() {
this.vote = function (user, voteItem, voteManager) {
console.log('请不要重复投票');
if (voteManager.mapVoteCount[user] >= 4) {
voteManager.mapState[user] = new SpliteVoteState();
}
};
} function SpliteVoteState() {
this.vote = function (user, voteItem, voteManager) {
var s = voteManager.mapVote[user]; if (s != null) {
delete voteManager.mapVote[user];
} console.log('你有恶意刷票行为,取消投票资格'); if (voteManager.mapVoteCount[user] >= 7) {
voteManager.mapState[user] = new BlackVoteState();
}
};
} function BlackVoteState() {
this.vote = function (user, voteItem, voteManager) {
console.log('进入黑名单,将禁止登录和使用本系统');
};
} function VoteManager() {
this.mapState = {};
this.mapVote = {};
this.mapVoteCount = {}; this.vote = function (user, voteItem) {
var oldVoteCount = this.mapVoteCount[user]; if (oldVoteCount == null) {
oldVoteCount = 0;
}
this.mapVoteCount[user] = ++oldVoteCount; var state = this.mapState[user];
if (state == null) {
state = new NormalVoteState();
} state.vote(user, voteItem, this);
};
} var vm = new VoteManager();
for (var i = 0; i < 8; i++) {
vm.vote('u1', 'A');
} // another way function VoteManager2() {
var mapState = {};
var mapVote = {};
var mapVoteCount = {}; this.vote = function (user, voteItem) {
var oldVoteCount = mapVoteCount[user]; if (oldVoteCount == null) {
oldVoteCount = 0;
}
mapVoteCount[user] = ++oldVoteCount; var state = mapState[user];
if (state == null) {
state = voteNormal;
} state(user, voteItem);
}; function voteNormal(user, voteItem) {
mapVote[user] = voteItem;
console.log('恭喜你投票成功');
// 正常投票完毕,维护下一个状态,同一个人再投票就重复了
return mapState[user] = voteRepeat;
} function voteRepeat(user, voteItem) {
console.log('请不要重复投票');
if (mapVoteCount[user] >= 4) {
return mapState[user] = voteSplite;
}
} function voteSplite(user, voteItem) {
var s = mapVote[user]; if (s != null) {
delete mapVote[user];
} console.log('你有恶意刷票行为,取消投票资格'); if (mapVoteCount[user] >= 7) {
return mapState[user] = voteBlack;
}
} function voteBlack(user, voteItem) {
console.log('进入黑名单,将禁止登录和使用本系统');
}
} var vm = new VoteManager2();
for (var i = 0; i < 8; i++) {
vm.vote('u1', 'A');
}
}()); (function () {
// 模拟工作流
/*
请假流程,需项目经理和部门经理审批
*/ // 公共状态处理机
function LeaveRequestContext() {
// 持有一个状态对象
this.state = null;
// 包含流程处理需要的业务数据对象
this.businessVO = null;
} LeaveRequestContext.prototype = {
// 执行工作
doWork: function () {
this.state.doWork(this);
}
}; // 定义请假单的业务数据模型
function LeaveRequestModel() {
// 请假人
this.user = '';
// 请假开始时间
this.beginDate = '';
// 请假天数
this.leaveDays = '';
// 审核结果
this.result = '';
} function ProjectManagerState() {
this.doWork = function (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; if (answer == 1) {
if (leaveRequestModel.leaveDays > 3) {
request.state = new DepManagerState();
} else {
request.state = new AuditOverState();
}
} else {
request.state = new AuditOverState();
} request.doWork();
};
} function DepManagerState() {
this.doWork = function (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; request.state = new AuditOverState(); request.doWork();
};
} function AuditOverState() {
this.doWork = function (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 LeaveRequestContext();
request.businessVO = lrm;
request.state = new ProjectManagerState(); request.doWork(); // another 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(); }()); /*
何时选用状态模式
1.如果一个对象的行为取决于它的状态,而且它必须在运行时刻根据状态来改变它的行为,可以使用状态模式把状态和行为分离。
2.如果一个操作中含有庞大的多分支语句,而且这些分支依赖于该对象的状态,可以使用状态模式,把各个分支的处理分散包装到单独的对象处理类中。 相关模式 状态模式和策略模式
两个结构相同。状态模式的行为是平行性的,不可相互替换的;而策略模式的行为是平等性的,可相互替换的。 状态模式和观察者模式
相似但又有区别,可以组合使用。
这两个模式都是在状态发生改变的时候触发行为,只不过观察者模式的行为是固定的,那就是通知所有观察者;而状态模式是根据状态来选择不同的处理。
从表面来看,两个模式相似,观察者模式中的被观察对象就好比状态模式中的上下文,观察者模式中当被观察对象的状态发生改变的时候,触发的通知所有观察者的方法就好比状态模式中,根据状态的变化选择对应的状态处理。
但实际这两个模式是不同的,观察者模式的目的是在被观察者的状态发生改变的时候,触发观察联动,具体如何处理观察者模式不管;而状态模式的主要目的在于根据状态来分离和选择行为,当状态发生改变的时候,动态地改变行为。
这两个模式可以组合使用,比如在观察者模式的观察者部分,当被观察对象的状态发生改变,触发通知了所有的观察者后,使用状态模式根据通知过来的状态选择相应的处理。 状态模式和单例模式
可以组合使用
把状态模式中的状态处理类实现成单例。 状态模式和享元模式
可以组合使用
由于状态模式把状态对应的行为分散到多个状态对象中,会造成很多细粒度的状态对象,可以把这些状态处理对象通过享元模式来共享,从而节省资源。
*/ (function () {
// http://www.dofactory.com/javascript-state-pattern.aspx
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));
}
}; // log helper 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();
}
}());
</script>
</body>
</html>

javascript设计模式--状态模式(State)的更多相关文章

  1. JavaScript设计模式 - 状态模式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. JavaScript设计模式——状态模式

    状态和行为: 所谓对象的状态,通常指的就是对象实例的属性的值:而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上. 状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应 ...

  3. C#设计模式——状态模式(State Pattern)

    一.概述在面向对象软件设计时,常常碰到某一个对象由于状态的不同而有不同的行为.如果用if else或是switch case等方法处理,对象操作及对象的状态就耦合在一起,碰到复杂的情况就会造成代码结构 ...

  4. 大话设计模式--状态模式 State -- C++实现实例

    1.状态模式: 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来就像是改变了其类. 状态模式解决的是当控制一个对象状态转换的条件表达式过于复杂, 把状态的判断逻辑转移到表示不同状态的一系列类 ...

  5. 【设计模式】Javascript设计模式——状态模式(行为型)

    注:这个模式是非常聪明的,很有点数学中组合的意思,现在,来看下这个模式是怎么个思想. 问题提出:假如某个操作有三种可能,分别为1,2,3,还可能是组合,比如先执行1,再执行2或者先执行2再执行3或者1 ...

  6. 深入浅出设计模式——状态模式(State Pattern)

    模式动机 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的.当一个这样的 ...

  7. 【转】设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  8. 设计模式 ( 十七) 状态模式State(对象行为型)

    设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...

  9. 乐在其中设计模式(C#) - 状态模式(State Pattern)

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

随机推荐

  1. ok6410的madplay配置

    二.移植嵌入式播放器 madplay madplay 播放器程序主要依赖于如下库: zlib   zlib-1.1.4.tar.gz 提供数据压缩用的函式库 libid3tag  libid3tag- ...

  2. NOJ1018-深度遍历二叉树

    题目要求很简单,前中后序遍历一棵二叉树.坑爹的是这道题的输入数据和测试数据压根不一样,找了好久原因,去讨论区看见有别人发的测试样例,修改了一下就AC了 测试样例是这个:DEH##FJ##G#CK### ...

  3. 菜鸟学习Hibernate——缓存

    Hibernate的缓存分为三种:一级缓存.二级缓存.查询缓存.下面我就为大家介绍一下. 一.概念. 一级缓存:第一级存放于session中称为一级缓存.Session 级别的缓存,它同session ...

  4. sql server 小记——分区表

    我们知道很多事情都存在一个分治的思想,同样的道理我们也可以用到数据表上,当一个表很大很大的时候,我们就会想到将表拆 分成很多小表,查询的时候就到各个小表去查,最后进行汇总返回给调用方来加速我们的查询速 ...

  5. SCSF智能客户端学习笔记(一)

    什么是智能客户端 要了解智能客户端,首先要认识瘦客户端技术和胖客户端技术各自的优缺点. 对于前者,典型的应用就是使用浏览器,通过输入URL远程访问服务端,并向服务端发送命令,获取服务端的资源,然后在客 ...

  6. Uncaught TypeError: Cannot read property 'insertAdjacentHTML' of null

    在开发Ext 项目中如果遇到 Uncaught TypeError: Cannot read property 'insertAdjacentHTML' of null 这个错误,检查下renderT ...

  7. C++变量的存储类别与作用域

    总结一下C++中变量的存储类别以及变量的作用域. (1)标示符的存储类别决定了标示符在内存中存在的时间(我们可以理解标示符就是确定一个变量的符号,也就是我们所说的变量名) 二:存储类别 (1)静态存储 ...

  8. 【BZOJ 2120】 数颜色

    Description 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会像你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜 ...

  9. Indigo Studio

    http://www.infragistics.com/products/indigo-studio?gclid=CIXrnav4lcQCFdclvQoduVEAnA

  10. Chrome控制台输入多行js

    Chrome控制台输入多行js 分类: chrome2013-09-08 09:40 342人阅读 评论(0) 收藏 举报 控制台 Chrome控制台中回车默认是执行,要想输入换行,应按Enter+S ...