js设计模式-单例模式、策略模式

问题场景:

设计一个路由网关的解决方案, 解决根据不同嵌套路由在访问同一个域名的情况下, 跳转不同的应用程序。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const url = 'http://url.com';

- 指向a平台的url地址:
`${url}/a/login` // a平台 登录页
`${url}/a/home` // a平台 主页
`${url}/a/user` // a平台 个人页
...

- 指向b平台的url地址:
`${url}/b/login` // b平台 登录页
`${url}/b/home` // b平台 主页
`${url}/b/user` // b平台 个人页
...

解决方法:

方案一: 参考 JavaScript 设计模式, 使用 单例模式+策略模式 实现。
使用单例模式实现网关的唯一性, 保证路由的准确性和统一性。
在首次实例化单例模式的同时, 使用策略模式选择网关对应配置方案。

单例模式优点:

  • 只需实例化一次, 减小内存使用压力
  • 创建实例化后, 不允许被修改

策略模式优点:

  • 同一个方法调用, 可通过策略判断选择
  • 避免创建多个 if-else

代码示例:

首先, 我们先创建一个通用的接口类SetSingle, 并暴露一个接口名 login()

1
2
3
4
// SetSingle.ts
export interface SetSingle {
login(): void;
}

然后创建不同的子类, 来实现通用接口类里的方法

1
2
3
4
5
6
7
8
9
// ASingle.ts
import { SetSingle } from '@/../SetSingle';

class ASingle implements SetSingle {
public login(): void {
console.log('ASingle login');
}
}
export default ASingle;
1
2
3
4
5
6
7
8
9
// BSingle.ts
import { SetSingle } from '@/../SetSingle';

class BSingle implements SetSingle {
public login(): void {
console.log('BSingle login');
}
}
export default BSingle;

我们再创建一个最关键的, 单例模式父类, 实例化方法getInstance(), 如果已经实例化方法一次, 则返回自身。

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
39
40
// Context.ts
import { SetSingle } from '@/../SetSingle';

class Context {
/**
* 使用 static 定义静态方法, 以静态方法或者枚举返回实例
* 使用 static 在堆内存开辟内存空间
* 在堆内存中实例化SetSingle里面的各个参数
* static 把对象指向堆内存空间
*/
private static instance: Context;
private single: SetSingle = null;

// 在构造函数里使用 this, 指向自身。
// 一般适用于构造函数内需要传参时使用
constructor() {
// Context.instance = this
}

public static getInstance() {
if (!Context.instance) {
Context.instance = new Context();
}
return Context.instance;
}

// 子类构造类
public SetSingle(single: SetSingle) {
if (this.single == null) {
this.single = single;
}
}

// 函数类
public login() {
this.single.login();
}
}

export default Context;

实例化与使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const context = Context.getInstance();

const path = pathToRegexp('/a/:path(.*)').exec(to.path + '');
if( path !== null ){

context.SetSingle(new ASingle());
context.login();
console.log(context.login()) // ASingle login

} else {

context.SetSingle(new BSingle());
context.login();
console.log(context.login()) // BSingle login
}

评论