# 前言
在行为型设计模式中,策略模式和状态模式在结构上非常的类似,并且在逻辑简化,去耦合上都是一个很好的解决方案。
有些小伙伴经常会分不清两者的区别,本文将来聊聊这两种模式。
本章节用 typescript
进行书写。
# 相同点
本质上,策略模式和状态模式都是干同一个事情,那就是去耦合。换句话说,就是把关注点进行分离,干什么以及怎么干分别放在不同的地方实现,从而减少我们逻辑上的耦合,也让我们的程序不用陷入 if...else..
地狱中去。
# 策略模式
策略模式,就是用什么策略干什么事情。简单来说,策略模式就是我们定义了一系列的算法,算法间彼此独立可切换。而关于如何使用这些策略,则由上层调用者来进行实现,非常灵活。
# 举个栗子
我们知道每个人的职责是不同的,比方说,学生的工作就是学习,农民的工作就是务农,医生的工作就是救死扶伤。那么,对于不同的身份,我们可以赋予不同的策略算法。
# 策略
首先,我们需要定义一批策略方法。
interface Istrategies {
[key: string]: () => any
}
const strategies: Istrategies = {
student: function () {
console.log('我在读书')
},
doctor: function () {
console.log('我在治病')
},
farmer: function () {
console.log('我在干农活')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们使用了对象来模拟一些列的策略类,并实现了 Istrategies
接口。其次,我们要实现一个环境类,对外提供调用接口。
# 对外接口
interface IstrategiesCtx {
work:(name: string) => void;
}
const strategiesCtx: IstrategiesCtx = (function () {
return {
work: function (name: string) {
strategies[name] && strategies[name].call(this)
}
}
})()
2
3
4
5
6
7
8
9
10
11
环境我们使用即时执行函数来模拟,导出接口。这样,我们就可以在任何地方随意切换使用了。
# 调用
strategiesCtx.work('student')
strategiesCtx.work('farmer')
strategiesCtx.work('doctor')
2
3
4
5
# 结果
# 状态模式
使用策略模式,我们想怎么切换怎么调用都行,强调了一个自主性。现在,我们希望自己维护一些状态,然后不再关心如何去调用了,也就是说我们把自主权转移给了第三方,而自己并不关心。
还是上面那个例子,我们分别对应着学生、医生和农民三个身份,不同身份状态下,我们都可以工作,只不过工作的东西就不一样了。
# 有限状态机
首先,我们实现一下我们的几种状态,内部维护状态,并且提供切换状态以及工作的接口。
interface IprofessionState {
change(val: string): void
work(): void
}
interface Ijob {
work (): void
}
interface Istate {
[key: string]: Ijob
}
const professionState: IprofessionState = (function() {
let state = 'student'
const _state: Istate = {
student: {
work: function () {
console.log('我正在读书')
}
},
farmer: {
work: function () {
console.log('我正在干农活')
}
},
doctor: {
work: function () {
console.log('我在治病')
}
}
}
return {
change: function (val) {
state = val
},
work: function () {
_state[state] && _state[state].work.call(this)
}
}
})()
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
39
40
41
42
其中,我们分别定义了三种状态,并且每一种状态都提供和一个 work
方法。其次,对外的 change
方法可以切换状态, 而 work
则是当前状态的工作方法。
# 调用
关于调用,我们可以实现一个 Person 类。
class Person {
private role: any
constructor (role) {
this.role = role
}
change (roleName) {
this.role.change(roleName)
}
handleWork () {
this.role.work()
}
}
const xiaoming = new Person(professionState)
xiaoming.handleWork()
xiaoming.change('doctor')
xiaoming.handleWork()
xiaoming.change('farmer')
xiaoming.handleWork()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Person
内部持有 role
,持有状态。当我们调用 change
赋予不同的角色时,handleWork
会有不同的表现。
# 结果
# 总结
总的来说,策略模式和状态模式还是有很多的相似之处,它们在结构上有很多类似的地方,同时都是去耦合的绝佳方式。在我们日常开发中,善用这两种模式都能够很好的分离关注点,也可以避免很多 if
分支的使用。
不同的是,策略模式讲究一批策略算法可以灵活切换,并且彼此独立。在调用方式上也都是主观程序控制,主动调用不同的策略来实现不同的功能,不需要维护一个状态。
而状态模式最大不同在于,状态模式会维护一个状态,并且不关心当前使用了哪一个算法,只需要切换到不同的状态,行为自然不同。这里敲黑板,切换状态,改变行为。