Skip to content

Commit d1ab32b

Browse files
committed
add ts for design pattern
1 parent 33b15cd commit d1ab32b

File tree

104 files changed

+1596
-33
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+1596
-33
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Design Pattern 23种经典设计模式源码详解
22

3-
23种经典设计模式,结合实际场景,源码详解,充分注释说明,每一行代码都经过检验,确保可靠。
3+
超过23种经典设计模式源码详解,结合实际场景,充分注释说明,每一行代码都经过检验,确保可靠。
44

55
用不同语言来实现,包括Java/JS/Python/TypeScript/Go等。
66

7-
Including 23 source code examples of classic design patterns, which are fully annotated in combination with actual scenarios. Every line of code has been verified to ensure reliability.
7+
Including over 23 source code examples of classic design patterns, which are fully annotated in combination with actual scenarios. Every line of code has been verified to ensure reliability.
88

99
Implemented in different languages, including Java/JS/Python/TypeScript/Go, etc.
1010

memento-pattern/ts/package.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "esm-project",
3+
"version": "1.0.0",
4+
"main": "test/test.js",
5+
"scripts": {
6+
"test": "node test/test.js"
7+
},
8+
"type": "module"
9+
}

memento-pattern/ts/src/Caretaker.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Memento } from './Memento.js'
2+
3+
// 负责人(Caretaker)角色,只负责保存备忘录记录,不能修改备忘录对象的内容
4+
export class Caretaker {
5+
mementoList: Memento[]
6+
constructor() {
7+
// 备忘录可以是一个记录,也可以就是一个对象,根据业务场景设置
8+
this.mementoList = []
9+
}
10+
11+
add(memento: Memento) {
12+
console.log(
13+
this.constructor.name +
14+
'::add() [memento = ' +
15+
memento.constructor.name +
16+
']'
17+
)
18+
this.mementoList.push(memento)
19+
}
20+
21+
get(index: number) {
22+
return this.mementoList[index]
23+
}
24+
25+
getMementoList() {
26+
return this.mementoList
27+
}
28+
}

memento-pattern/ts/src/Memento.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// 备忘录(Memento)角色,负责存储发起人传入的状态
2+
export class Memento {
3+
state: string
4+
constructor(state: string) {
5+
console.log(this.constructor.name + '::Memento() [state = ' + state + ']')
6+
this.state = state
7+
}
8+
9+
getState() {
10+
return this.state
11+
}
12+
13+
setState(state: string) {
14+
this.state = state
15+
}
16+
}

memento-pattern/ts/src/Originator.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Memento } from './Memento.js'
2+
3+
// 发起人(Originator)负责生成状态快照,即利用一个新备忘录对象将自己的内部状态存储起来
4+
export class Originator {
5+
state: string
6+
constructor() {}
7+
8+
// 每次创建一个新备忘录来保存状态
9+
saveMemento() {
10+
console.log(
11+
this.constructor.name + '::saveMemento() [state = ' + this.state + ']'
12+
)
13+
return new Memento(this.state)
14+
}
15+
16+
// 从备忘录中恢复状态
17+
restoreMemento(memento: Memento) {
18+
this.state = memento.getState()
19+
}
20+
21+
getState() {
22+
return this.state
23+
}
24+
25+
setState(state: string) {
26+
this.state = state
27+
}
28+
}

memento-pattern/ts/test/test.html

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script type="module">
2+
// module need run in http server
3+
import { test } from './test.js'
4+
alert('pls look console info.' + '\n\r' + test)
5+
</script>

memento-pattern/ts/test/test.ts

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { Originator } from '../src/Originator.js'
2+
import { Caretaker } from '../src/Caretaker.js'
3+
4+
export function test() {
5+
/*
6+
* 备忘录模式是在不暴露对象实现细节的情况下保存和恢复对象之前的状态。
7+
* 先声明发起人Originator,再声明负责人Caretaker,发起人生成备忘录Memento
8+
* 通过负责人则保存备忘录历史记录,读取备忘录由负责人来完成。
9+
*/
10+
const originator = new Originator()
11+
const careTaker = new Caretaker()
12+
// 发起人产生一个状态
13+
originator.setState('state1')
14+
// 覆盖了状态,那么前面的状态未保存
15+
originator.setState('state2')
16+
// 发起人生成备忘录,一般添加时直接保存即可
17+
const memento = originator.saveMemento()
18+
// 负责人保添加备忘录历史记录
19+
careTaker.add(memento)
20+
21+
// 直接生成备忘录并添加到负责人的备忘录列表
22+
originator.setState('state3')
23+
careTaker.add(originator.saveMemento())
24+
originator.setState('state4')
25+
careTaker.add(originator.saveMemento())
26+
27+
console.log('发起人当前的状态: ' + originator.getState())
28+
29+
// 发起人通过负责人那里取出状态
30+
originator.restoreMemento(careTaker.get(0))
31+
console.log('第一个保存的状态: ' + originator.getState())
32+
originator.restoreMemento(careTaker.get(1))
33+
console.log('第二个保存的状态: ' + originator.getState())
34+
35+
// 遍历全部备忘录
36+
for (let i = 0; i < careTaker.getMementoList().length; i++) {
37+
// 外部一般不直接访问备忘录里面的状态,而是逐个恢复备忘录,再取出状态来
38+
originator.restoreMemento(careTaker.get(i))
39+
console.log('state: ' + i + ')' + originator.getState())
40+
}
41+
}
42+
43+
// 执行测试
44+
;(function () {
45+
console.log('test start:')
46+
test()
47+
})()
48+
49+
/**
50+
// use ems
51+
jarry@jarrys-MacBook-Pro ts % ts-node-esm test/test.ts
52+
// or tsc and node run
53+
jarry@jarrys-MacBook-Pro ts % tsc
54+
jarry@jarrys-MacBook-Pro ts % node test/test.js
55+
test start:
56+
Originator::saveMemento() [state = state2]
57+
Memento::Memento() [state = state2]
58+
Caretaker::add() [memento = Memento]
59+
Originator::saveMemento() [state = state3]
60+
Memento::Memento() [state = state3]
61+
Caretaker::add() [memento = Memento]
62+
Originator::saveMemento() [state = state4]
63+
Memento::Memento() [state = state4]
64+
Caretaker::add() [memento = Memento]
65+
发起人当前的状态: state4
66+
第一个保存的状态: state2
67+
第二个保存的状态: state3
68+
state: 0)state2
69+
state: 1)state3
70+
state: 2)state4
71+
*/

memento-pattern/ts/tsconfig.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"target": "esnext",
4+
"lib": ["esnext", "dom"],
5+
"module": "esnext",
6+
"strict": true,
7+
"removeComments": true,
8+
"forceConsistentCasingInFileNames": true,
9+
"strictPropertyInitialization": false,
10+
"esModuleInterop": true,
11+
"skipLibCheck": true,
12+
},
13+
"include": [
14+
"src/**/*.ts",
15+
"test/*.ts",
16+
]
17+
}

observer-pattern/java/test/Test.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static void start() {
1919

2020
// 也可以单独给主题注册一个新的观察者
2121
concreteSubject.register(new ConcreteObserver2());
22-
// 可以移除观察者对象
22+
// 可以移除观察者对象,可以打开注释试下
2323
// concreteSubject.remove(observer1);
2424

2525
// 主题开始发布新通知,各观察者自动更新

observer-pattern/js/test/test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function test() {
1616
// 也可以单独给主题注册一个新的观察者
1717
const observer2 = new ConcreteObserver2()
1818
concreteSubject.register(observer2)
19-
// 可以移除观察者对象
19+
// 可以移除观察者对象,可以打开注释试下
2020
// concreteSubject.remove(observer1)
2121

2222
// 主题开始发布新通知,各观察者自动更新

observer-pattern/ts/package.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "esm-project",
3+
"version": "1.0.0",
4+
"main": "test/test.js",
5+
"scripts": {
6+
"test": "node test/test.js"
7+
},
8+
"type": "module"
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { ObserverAPI } from './ObserverAPI.js'
2+
import { Subject } from './Subject.js'
3+
4+
// 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
5+
// 不同的观察者也可以对应多个主题
6+
export class ConcreteObserver extends ObserverAPI {
7+
// 给观察者绑定主题,同时把观察者添加到主题列表
8+
subject: Subject
9+
constructor(subject: Subject, name: string) {
10+
super(name)
11+
this.subject = subject
12+
subject.register(this)
13+
}
14+
15+
// 观察者发出更新通知,不用单独告诉订阅者,由订阅者自行监听
16+
update(content: string) {
17+
console.log(
18+
`${this.constructor.name}::update() [subject.name = ${this.subject.name} content = ${content}]`
19+
)
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { ObserverAPI } from './ObserverAPI.js'
2+
3+
// 具体的观察者实现类,也可以看成订阅者,关联对应的主题类。
4+
// 不同的观察者可以对应不同的主题。
5+
export class ConcreteObserver2 extends ObserverAPI {
6+
// 这里没有在构造器就绑定某个主题,而是从客户角度去注册观察者
7+
// 观察者发出更新通知,观察者自行监听
8+
update(content: string) {
9+
console.log(`${this.constructor.name}::update() [content = ${content}]`)
10+
}
11+
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ObserverAPI } from './ObserverAPI'
2+
import { Subject } from './Subject.js'
3+
4+
// 观察者主题类,也是发布者,重写具体的通知方法。不同主题可以关联不同的观察者。
5+
export class ConcreteSubject extends Subject {
6+
// 不同的主题类有自己的通知方法,批量通知绑定的观察者
7+
notify(content: string) {
8+
console.log(
9+
this.constructor.name + '::notify() [content = ' + content + ']'
10+
)
11+
12+
this.observers.forEach((observer: ObserverAPI) => {
13+
observer.update(content)
14+
})
15+
16+
// for (const observer of this.observers) {
17+
// observer[0].update(content)
18+
// }
19+
}
20+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// 观察者抽象父类,定义一些公共方法
2+
export class ObserverAPI {
3+
name: string
4+
constructor(name: string) {
5+
this.name = name || this.constructor.name
6+
}
7+
8+
// 观察者发出更新通知,观察者自行监听
9+
update(content: string) {
10+
console.log(`${this.constructor.name}::update() [content = ${content}]`)
11+
}
12+
13+
setName(name: string) {
14+
this.name = name
15+
}
16+
}

observer-pattern/ts/src/Subject.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ObserverAPI } from './ObserverAPI.js'
2+
3+
// 定义抽象主题类或者接口,供具体主题类继承
4+
export abstract class Subject {
5+
name: string
6+
observers: Set<ObserverAPI>
7+
constructor(name: string) {
8+
this.name = name
9+
this.observers = new Set<ObserverAPI>()
10+
}
11+
12+
getName() {
13+
return this.name
14+
}
15+
16+
setName(name: string) {
17+
this.name = name
18+
}
19+
20+
register(observer: ObserverAPI) {
21+
console.log(
22+
this.constructor.name +
23+
'::register() [observer = ' +
24+
observer.constructor.name +
25+
']'
26+
)
27+
this.observers.add(observer)
28+
}
29+
30+
remove(observer: ObserverAPI) {
31+
this.observers.delete(observer)
32+
}
33+
34+
// 通知由具体类来实现逻辑
35+
abstract notify(name: string): void
36+
}

observer-pattern/ts/test/test.html

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script type="module">
2+
// module need run in http server
3+
import { test } from './test.js'
4+
alert('pls look console info.' + '\n\r' + test)
5+
</script>

observer-pattern/ts/test/test.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ConcreteSubject } from '../src/ConcreteSubject.js'
2+
import { ConcreteObserver } from '../src/ConcreteObserver.js'
3+
import { ConcreteObserver2 } from '../src/ConcreteObserver2.js'
4+
5+
export function test() {
6+
/**
7+
* 观察者模式应用非常广泛,主要是观察者提前绑定到发布者
8+
* 当发布者发布消息时,批量广播通知,而无需逐一通知
9+
* 观察者监听到消息后自己决定采取哪一种行为
10+
*/
11+
12+
// 定义一个主题,也就是发布者
13+
const concreteSubject = new ConcreteSubject('subject1')
14+
// 再声明观察者,通过构造器注册到主题上s
15+
const observer1 = new ConcreteObserver(concreteSubject, 'observer1')
16+
// 也可以单独给主题注册一个新的观察者
17+
const observer2 = new ConcreteObserver2('observer2')
18+
concreteSubject.register(observer2)
19+
// 可以移除观察者对象,可以打开注释试下
20+
// concreteSubject.remove(observer1)
21+
22+
// 主题开始发布新通知,各观察者自动更新
23+
concreteSubject.notify('hello, this is broadcast.')
24+
}
25+
26+
// 执行测试
27+
;(function () {
28+
console.log('test start:')
29+
test()
30+
})()
31+
/**
32+
// use ems
33+
jarry@jarrys-MacBook-Pro ts % ts-node-esm test/test.ts
34+
// or tsc and node run
35+
jarry@jarrys-MacBook-Pro ts % tsc
36+
jarry@jarrys-MacBook-Pro ts % node test/test.js
37+
test start:
38+
ConcreteSubject::register() [observer = ConcreteObserver]
39+
ConcreteSubject::register() [observer = ConcreteObserver2]
40+
ConcreteSubject::notify() [content = hello, this is broadcast.]
41+
ConcreteObserver::update() [subject.name = subject1 content = hello, this is broadcast.]
42+
ConcreteObserver2::update() [content = hello, this is broadcast.]
43+
*/

0 commit comments

Comments
 (0)