JS设计模式大合集

仓库地址:JS设计模式大合集
欢迎大家 Star ,一起交流学习!

策略模式是个啥

策略模式(Strategy Pattern)是一种常见的设计模式,它允许在运行时选择算法的行为。这种模式使得算法可以独立于其使用者而变化。在JavaScript中,策略模式经常用于将一组算法封装成独立的对象,并且使它们在需要时可以相互替换。

理解策略模式

策略模式通过定义一系列的算法,将它们封装成独立的策略对象,然后在运行时根据需要选择适当的策略对象。这种方式可以使得算法的变化独立于使用算法的客户端代码。策略模式通常包含以下角色:

  • 环境(Context):环境类包含一个对策略对象的引用,并且可以在运行时切换不同的策略对象。
  • 策略接口(Strategy Interface):定义了一组算法的接口,所有具体策略类都实现了该接口。
  • 具体策略(Concrete Strategy):实现了策略接口的具体算法。

举个例子

可能理论说的还是一头雾水,下面我们通过简单的例子来理解策略模式。

例如,我需要一个通用的算法,用来计算图像的面积。那么假设图像分别有:

  • 圆形(circle)
  • 方形(rectangle)
  • 三角形(triangle)

他们的计算面积公式如下:

1
2
3
const circle = (radius: number) => Math.PI * radius ** 2
const rectangle = (width: number, height: number) => width * height
const triangle = (base: number, height: number) => 0.5 * base * height

那么,我们可以把这些计算规则整理起来,定义一套通用策略:

1
2
3
4
5
const shapeStrategy = {
circle: (radius) => Math.PI * radius ** 2,
rectangle: (width, height) => width * height,
triangle: (base, height) => 0.5 * base * height
} as const;
as const 是个啥?

这个是ts的语法哦
使用as const后,shapeStrategy的类型会被推断为: 
 {
   readonly circle: (radius: number) => number;
   readonly rectangle: (width: number, height: number) => number;
   readonly triangle: (base: number, height: number) => number;
 }
可以确保shapeStrategy对象的属性被推断为具体的函数类型,而不是更一般的函数类型。
这样,当你使用shapeStrategy对象时,TypeScript编译器会提供更精确的类型检查。

定义好之后,接下来,我们用class来整合上面的策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ShapeCalculator<T> {
private strategy: (...args: T[]) => number;

constructor(strategy: (...args: T[]) => number) {
this.strategy = strategy;
}

setStrategy(strategy: (...args: T[]) => number) {
this.strategy = strategy;
}

calculate(...args: T[]): number {
return this.strategy(...args);
}
}
T是个啥?

这个也是ts的语法哦
表示范型,也就是通用类型,当传入的参数是 number,则返回值的类型就是number,
传入参数是string,则返回值就是string,T是一个可变动的类型,根据传入的类型而变化

好了,我们来整体调用看看:

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
const shapeStrategy = {
circle: (radius: number) => Math.PI * radius ** 2,
rectangle: (width: number, height: number) => width * height,
triangle: (base: number, height: number) => 0.5 * base * height
} as const;

class ShapeCalculator<T> {
private strategy: (...args: T[]) => number;

constructor(strategy: (...args: T[]) => number) {
this.strategy = strategy;
}

setStrategy(strategy: (...args: T[]) => number) {
this.strategy = strategy;
}

calculate(...args: T[]): number {
return this.strategy(...args);
}
}

// 计算圆的面积
const circleCalculator = new ShapeCalculator<number>(shapeStrategy.circle);

// 计算矩形的面积
const rectangleCalculator = new ShapeCalculator<number>(shapeStrategy.rectangle);

// 使用计算器
console.log(circleCalculator.calculate(10)); // 输出圆的面积
console.log(rectangleCalculator.calculate(10, 20)); // 输出矩形的面积

实际应用场景

策略模式在实际应用中有着广泛的用途,特别是在需要根据不同情况使用不同算法的场景下。以下是一些常见的实际应用场景:

  • 表单验证:根据表单的不同字段类型,可以使用不同的验证策略来验证用户输入。
  • 排序算法:根据数据量大小、数据类型等因素,可以选择不同的排序算法,如快速排序、冒泡排序等。
  • 支付方式:根据用户的支付方式,可以选择不同的支付策略,如信用卡支付、支付宝支付等。

结语

策略模式是一种强大而灵活的设计模式,它允许在运行时动态地选择算法,从而使得代码更加灵活、可维护和可扩展。在JavaScript中,策略模式可以通过对象字面量、函数传递等方式简单地实现,为代码的组织和维护提供了便利。通过深入理解和合理应用策略模式,我们可以写出更加优雅和高效的JavaScript代码。