Node.js 设计模式笔记 —— Template 模式

Template 模式与 Strategy 模式有很多相似之处。Template 模式首先会定义一个虚拟基类,描述某个组件的骨架(即通用的部分),同时令骨架中存在的某些步骤处于未定义状态。
之后由虚拟基类的子类来实现上述组件中缺失的未定义部分,这部分之前未定义的方法称为 template methods
此模式的目的在于,定义一系列属于“同一家族”的类,能够囊括某个组件的所有变体。

UML of Template pattern

Template 和 Strategy 模式的目的是非常相似的,它们之间的区别主要在于结构和实现。
两者都允许我们在共享组件中通用部分的同时,修改组件中变化的部分,以此形成不同的变体。不同的地方在于,Strategy 是在运行时动态实现的,而 Template 则在子类定义的时刻就已经被确定了。

配置管理模板

1
2
3
mkdir template && cd template
npm install ini
npm install objec-path

package.json

1
2
3
{
"type": "module"
}

configTemplate.js

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
import {promises as fsPromises} from 'fs'
import objectPath from 'object-path'

export class ConfigTemplate {
async load(file) {
console.log(`Deserializing from ${file}`)
this.data = this._deserialize(
await fsPromises.readFile(file, 'utf-8')
)
}

async save(file) {
console.log(`Serializing to ${file}`)
await fsPromises.writeFile(file, this._serialize(this.data))
}

get(path) {
return objectPath.get(this.data, path)
}

set(path, value) {
return objectPath.set(this.data, path, value)
}

_serialize() {
throw new Error('_serialize() must be implemented')
}

_deserialize() {
throw new Error(`_deserialize() must be implemented`)
}
}

其中 configTemplate 虚拟基类实现了配置管理逻辑中的通用部分,即加载和保存文件、获取和设置属性。同时不对序列化和反序列化部分的逻辑进行定义,从而可以通过再创建不同的 Config 子类(即后面的 jsonConfiginiConfig)来实现具体的序列化逻辑,进而支持特定的配置文件格式。

jsonConfig.js

1
2
3
4
5
6
7
8
9
10
11
import {ConfigTemplate} from './configTemplate.js'

export class JsonConfig extends ConfigTemplate {
_deserialize(data) {
return JSON.parse(data)
}

_serialize(data) {
return JSON.stringify(data, null, ' ')
}
}

iniConfig.js

1
2
3
4
5
6
7
8
9
10
11
12
import {ConfigTemplate} from './configTemplate.js'
import ini from 'ini'

export class IniConfig extends ConfigTemplate {
_deserialize(data) {
return ini.parse(data)
}

_serialize(data) {
return ini.stringify(data)
}
}

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {JsonConfig} from './jsonConfig.js'
import {IniConfig} from './iniConfig.js'

async function main() {
const jsonConfig = new JsonConfig()
await jsonConfig.load('samples/conf.json')
jsonConfig.set('nodejs', 'design patterns')
await jsonConfig.save('samples/conf_mod.json')

const iniConifg = new IniConfig()
await iniConifg.load('samples/conf.ini')
iniConifg.set('nodejs', 'design patterns')
await iniConifg.save('samples/conf_mod.ini')
}

main()

参考资料

Node.js Design Patterns: Design and implement production-grade Node.js applications using proven patterns and techniques, 3rd Edition