盒子
盒子
文章目录
  1. 状态模式:

状态模式

也是第一次听说这个状态模式, 也是学习的方式来写一下这个模式的简单理解;

状态模式:

(state), 当一个对象的内部状态发生改变时, 会导致其行为的改变, 看起来像是改变了对象

举个栗子: 有一个人去掷骰子, 犹豫没有做手脚(你懂的), 所以, 一直都是看运气.

首先, 定义一个奖品数组:

1
let prizes = ['prize1', 'prize2', 'prize3', 'prize4', 'prize5', 'prize6'];

接下来定义一个1~6的随机函数来充当骰子, 如下:

1
2
3
4
let dice = (() => {
let result = Math.floor(Math.random()*6+1);
return { res: result};
})();

现在已经准备完毕, 我们需要让一个人来掷骰子, 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(endRes => {
if(endRes === 1){
console.log('您获得了'+test[0]);
}else if(endRes === 2){
console.log('您获得了'+test[1]);
}else if(endRes === 3){
console.log('您获得了'+test[2]);
}else if(endRes === 4){
console.log('您获得了'+test[3]);
}else if(endRes === 5){
console.log('您获得了'+test[4]);
}else if(endRes === 6){
console.log('您获得了'+test[5]);
}
})(dice.res)

然后控制台打印吃了6以内的随机奖品

接下来我们看看一个多种比较复制的条件和逻辑时的状态模式形式, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let State = ( () => {
let States = {
state0: (params) => {
console.log('state0~');
},
state1: (params) => {
console.log('state1~');
},
state2: (params) => {
console.log('state2~');
},
state3: (params) => {
console.log('state3~');
}
};
let getResult = (result) => {
States['state' + result] && States['state' + result]();
};
return { setState: getResult };
})();

这里的处理方式明显要感觉清爽许多, 并且各个分支很独立, 我们可以对于通用变量, 函数等进行罗列, 组装等, 灵活性可谓是大大的增强~

此时我们看看其中一个状态下的处理, 调用和控制台输出如下所示:

1
2
3
State.setState(1);
state1~

这里我们也可以定义一个log函数来进一步的状态做一个监控, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
let log = (() => {
let info = '';
return {
set: msg => {
info += msg + '\n';
},
getAll: () => {
console.log(info);
info = '';
}
};
})();

这里我们定义了添加方法set和获取日志方法getAll.接下来我们找个例子看看

我一个朋友最近入手了一台mac,哈哈,我们就mac的操作方式做一个例子吧,mac可以通过键盘,触控板,鼠标来进行界面操作。我们用状态模式来定义这么一个构造器,代码如下,主要注释已经写好~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
let MacState = () => {
let _needState = {};
states = {
keyBoard: () => {
log.set('keyBoard -> 敲击了一下');
},
touchPad: () => {
log.set('touchPad -> 操作一下');
},
mouse: () => {
log.set('mouse -> 按一下');
}
};
let Action = {
addStates: (...arg) => {
//清空操作对象
_needState = {};
// 遍历添加动作
if(arg.length) {
arg.forEach( (n) => {
_needState[i] = true;
});
}
return this;
},
mission: () => {
for(key in _needState) {
states[key] && states[key]();
}
return this;
},
};
return {
addStates: Action.addStates,
mission: Action.mission
};
}

我们来仔细看看上面代码上的优势, 把我们想要的功能和状态封装到了一个方法, 其中内部包含契约好的状态, 以及对应状态的执行方法, 还有具体的操作方式, 然后返回对应做操的对象,

接下来让我们调用这个方法

1
2
3
4
5
mac.addStates('touchPad','mouse')
.mission()
.addStates('keyBoard')
.mission();
log.getAll();

上面是用的是function的方法来写的, 也完全可以使用class来写

1
2
3
touchPad -> 操作一下
mouse -> 按一下
keyBoard -> 敲击了一下

嗯嗯,还可以,每一个操作都记录到了~。就这样我们算是结束了对状态模式的认知。其实每种模式所解决的问题都是显而易见的,我们一路写下来会发现,状态模式解决了多个分支判断过程中代码的臃肿问题,解决了状态间的耦合,对于分支的增加与修改也很清晰的可以做到。哈哈,好吧,这就是我们的状态模式。

想想我们做电商中的订单系统, 完全就可以使用状态模式来写.

JS Bin on jsbin.com

原文在这里