如何在 TypeScript 中使用和实现策略模式来解决 Web 项目中的实际问题。
欢迎来到 TypeScript 中的设计模式系列,它介绍了使用TypeScript进行Web开发的一些有用的设计模式。
系列文章如下:
- 设计模式:(Builder Pattern)生成器模式
- 设计模式:(Chain of Responsibility Pattern)责任链模式
- 设计模式:(Observer Pattern) 观察者模式
- 设计模式:(Template Method Pattern)模板方法模式
- 适配器模式: (Adapter Pattern)适配器模式
设计模式对 Web 开发人员来说非常重要,我们可以通过掌握它们来编写更好的代码。在本文中,我将使用TypeScript来介绍策略模式。
注册和登录是 Web 应用程序中的重要功能。注册 Web 应用程序时,更常见的注册方式是使用账户/密码、电子邮件或手机。注册成功后,就可以使用相应的方法登录了。
function login(mode) {
if (mode === 'account') {
loginWithPassword();
} else if (mode === 'email') {
loginWithEmail();
} else if (mode === 'mobile') {
loginWithMobile();
}
}
当需要支持更多的第三方平台登录方式时,我们需要修之前的login函数:
function login(mode) {
if (mode === 'account') {
loginWithPassword();
} else if (mode === 'email') {
loginWithEmail();
} else if (mode === 'mobile') {
loginWithMobile();
} else if (mode === 'weixin') {
loginWithWeixin();
} else if (mode === 'juejin') {
loginWithJuejin()
}
}
如果以后我们继续添加或修改登录方式,我们会发现该login功能变得越来越难以维护。对于这个问题,我们可以使用策略模式将不同的登录方式封装成不同的登录策略。
为了更好的理解下面的代码,我们先看看对应的UML图:
在上图中,我们定义了一个Strategy接口
interface Strategy {
authenticate(args: any[]):boolean
}
// 第三方登录类
class JuejinStrategy implements Strategy {
authenticate(args: any[]) {
const [token] = args;
if (token !== "password") {
return false;
}
return true;
}
}
// 本地登录类
class LocalStrategy implements Strategy {
authenticate(args: any[]) {
const [username, password] = args;
if (username !== "kevin" && password !== "password123") {
return false;
}
return true;
}
}
有了不同的登录策略后,我们定义一个Authenticator类来在不同的的登录策略之间切换,并进行相应的认证操作
class Authenticator {
strategies: Record<string, Strategy> = {}
use(name:string, strategy:Strategy) {
this.strategies[name] = strategy
}
authenticate(name:string, ...args:any) {
if(!this.strategies[name]) {
return false
}
return this.strategies[name].authenticate.apply(null, args)
}
}
通过Authenticator 类来调用不用的登录方式
const auth = new Authenticator()
auth.use('local', new LocalStrategy())
auth.use('juejin', new JuejinStrategy())
function login(mode: string, ...args: any) {
return auth.authenticate(mode, args);
}
login("juejin", "password123");
login("local", "kevin", "password123");
除了登录认证场景外,策略模式还可以用在表单字段验证场景中。它还可以用于优化 if else 分支过多的问题。
如果使用 Node.js 开发认证服务,可以看一下passport.js模块
最后总结一下策略模式的使用场景:
- 当系统需要动态选择几种算法中的一种时,可以将每种算法封装成一个策略类。
- 多个类只是行为不同,您可以使用策略模式在运行时动态选择要执行的具体行为。