如何在 TypeScript 中使用和实现 Strategy 模式来解决 Web 项目中的实际问题。
欢迎来到 TypeScript 设计模式系列,该系列介绍了使用 TypeScript 进行 Web 开发的一些有用的设计模式。
每个工程师都应该知道的9种设计模式https://blog.csdn.net/wannianchuan/article/details/135565734
设计模式对于 web 开发人员来说非常重要,掌握它们可以让我们写出更好的代码。在本文中,我将使用 TypeScript 来介绍策略模式。
注册和登录是Web应用程序中的重要功能。在注册Web应用程序时,更常见的注册方式是使用帐户/密码、电子邮件或手机号码。一旦您成功注册,就可以使用相应的方法登录。
function login(mode) {
if (mode === "account") {
loginWithPassword();
} else if (mode === "email") {
loginWithEmail();
} else if (mode === "mobile") {
loginWithMobile();
}
}
当web应用需要支持其他登录方式时,例如,除了email登录方式外,Medium登录页面还支持第三方平台如Google、Facebook、Apple和Twitter的登录方式。
然后为了支持多个第三方登录方法,我们需要修改前面的 login
函数:
function login(mode) {
if (mode === "account") {
loginWithPassword();
} else if (mode === "email") {
loginWithEmail();
} else if (mode === "mobile") {
loginWithMobile();
} else if (mode === "google") {
loginWithGoogle();
} else if (mode === "facebook") {
loginWithFacebook();
} else if (mode === "apple") {
loginWithApple();
} else if (mode === "twitter") {
loginWithTwitter();
}
}
如果我们以后继续添加或修改登录方法,我们会发现 login
函数变得越来越难以维护,针对这个问题,我们可以使用策略模式将不同的登录方法封装到不同的登录策略中。
为了更好地理解下面的代码,让我们先看看相应的 UML 图:
在上面的图中,我们定义了一个 Strategy
接口,然后基于这个接口实现了 Twitter 和帐户/密码两种登录策略。
策略接口
interface Strategy {
authenticate(args: any[]): boolean;
}
TwitterStrategy类
class TwitterStrategy implements Strategy {
authenticate(args: any[]) {
const [token] = args;
if (token !== "tw123") {
console.error("Twitter account authentication failed!");
return false;
}
console.log("Twitter account authentication succeeded!");
return true;
}
}
LocalStrategy类
class LocalStrategy implements Strategy {
authenticate(args: any[]) {
const [username, password] = args;
if (username !== "bytefer" || password !== "666") {
console.log("Incorrect username or password!");
return false;
}
console.log("Account and password authentication succeeded!");
return true;
}
}
在拥有不同的登录策略之后,我们定义了一个 Authenticator 类来在不同的登录策略之间切换,并执行相应的身份验证操作。
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]) {
console.error("Authentication policy has not been set!");
return false;
}
return this.strategies[name].authenticate.apply(null, args);
}
}
之后,我们可以使用不同的登录方法,以以下方式实现用户身份验证:
const auth = new Authenticator();
auth.use("twitter", new TwitterStrategy());
auth.use("local", new LocalStrategy());
function login(mode: string, ...args: any) {
return auth.authenticate(mode, args);
}
login("twitter", "123");
login("local", "bytefer", "666");
当你成功运行上述代码时,相应的输出如下图所示:
除了登录身份验证场景,策略模式还可以用于表单字段验证场景,还可以用于优化 if else 分支过多的问题。
如果你使用 Node.js 开发身份验证服务,你可以看看 passport.js 模块:
Passport是Node.js的身份验证中间件,非常灵活和模块化,可以被轻易地添加到任何基于Express的Web应用中。它提供了一组全面的策略,支持使用用户名和密码、Facebook、Twitter等进行身份验证。
https://www.passportjs.org/
这个模块非常强大,目前支持多达538种策略:
最后,让我们总结一下策略模式的使用场景:
-
当系统需要动态地从几个算法中选择一个时,每个算法都可以封装到策略类中。
-
多个类只是在行为上不同,您可以使用策略模式来动态选择在运行时执行的特定行为。
如果您有任何问题,请随时给我留言。我以后会继续介绍其他的模式,如果您感兴趣,您可以关注文本魔术公众号以便能第一时间收到更新。