策略设计模式在Js中的应用

158 阅读3分钟

策略设计模式(Strategy Design Pattern)

定义

  • 一种行为型设计模式,它允许在运行时根据不同的算法或策略选择不同的行为。
  • 该模式将算法封装成独立的类,并使它们可以相互替换,从而使得算法的变化独立于使用它的客户端

核心思想

  • 策略设计模式的核心思想是将不同的算法或策略封装到各自的策略类中,这些策略类都实现了一个共同的接口。
  • 在使用这些策略的客户端中,通过将具体的策略对象传递给客户端,来实现动态选择和切换不同的策略。

参与者

1.\color{blue}{1.} 策略接口:规定策略的结构

2.\color{blue}{2.} 具体策略类:实现策略接口,暴露使用此策略的方法

3.\color{blue}{3.} 上下文类:保持对策略的引用并且可以设置/切换具体的策略;向外暴露出完成任务的方法

4.\color{blue}{4.} 客户端:构建并调用上下文对象完成具体的任务

示例

// 定义策略接口
interface Strategy {
  execute(): void;
}

// 具体策略类 - 策略A
class ConcreteStrategyA implements Strategy {
  execute(): void {
    console.log("Executing strategy A");
  }
}

// 具体策略类 - 策略B
class ConcreteStrategyB implements Strategy {
  execute(): void {
    console.log("Executing strategy B");
  }
}

// 上下文类
class Context {
  private strategy: Strategy;

  // 设置策略
  setStrategy(strategy: Strategy): void {
    this.strategy = strategy;
  }

  // 执行策略
  executeStrategy(): void {
    this.strategy.execute();
  }
}

// 使用策略设计模式
const context = new Context();

// 使用策略A
context.setStrategy(new ConcreteStrategyA());
context.executeStrategy();

// 使用策略B
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy();

复杂示例

以下是一个稍复杂的示例,使用 TypeScript 实现一个电商平台的促销策略:

`// 定义策略接口
interface PromotionStrategy {
  applyDiscount(price: number): number;
}

// 具体策略类 - 满减策略
class FullReductionStrategy implements PromotionStrategy {
  private threshold: number;
  private discountAmount: number;

  constructor(threshold: number, discountAmount: number) {
    this.threshold = threshold;
    this.discountAmount = discountAmount;
  }

  applyDiscount(price: number): number {
    if (price >= this.threshold) {
      return price - this.discountAmount;
    }
    return price;
  }
}

// 具体策略类 - 打折策略
class DiscountStrategy implements PromotionStrategy {
  private discountRate: number;

  constructor(discountRate: number) {
    this.discountRate = discountRate;
  }

  applyDiscount(price: number): number {
    return price * (1 - this.discountRate);
  }
}

// 上下文类
class ShoppingCart {
  private strategy: PromotionStrategy;
  private items: { name: string; price: number }[];

  constructor() {
    this.items = [];
  }

  addItem(item: { name: string; price: number }): void {
    this.items.push(item);
  }

  setPromotionStrategy(strategy: PromotionStrategy): void {
    this.strategy = strategy;
  }

  calculateTotalPrice(): number {
    let totalPrice = 0;
    for (const item of this.items) {
      totalPrice += item.price;
    }
    if (this.strategy) {
      totalPrice = this.strategy.applyDiscount(totalPrice);
    }
    return totalPrice;
  }
}

// 使用策略设计模式
const cart = new ShoppingCart();

cart.addItem({ name: "Product 1", price: 100 });
cart.addItem({ name: "Product 2", price: 200 });

// 使用满减策略
cart.setPromotionStrategy(new FullReductionStrategy(150, 20));
console.log(
  "Total price with full reduction strategy:",
  cart.calculateTotalPrice()
);

// 使用打折策略
cart.setPromotionStrategy(new DiscountStrategy(0.1));
console.log("Total price with discount strategy:", cart.calculateTotalPrice());`

多个策略切换

// 定义策略接口
interface Strategy {
  execute(): void;
}

// 具体策略类 - 策略A
class ConcreteStrategyA implements Strategy {
  execute(): void {
    console.log("Executing strategy A");
  }
}

// 具体策略类 - 策略B
class ConcreteStrategyB implements Strategy {
  execute(): void {
    console.log("Executing strategy B");
  }
}

// 上下文类
class Context {
  private strategyForPart1: Strategy;
  private strategyForPart2: Strategy;

  // 设置部分1的策略
  setStrategyForPart1(strategy: Strategy): void {
    this.strategyForPart1 = strategy;
  }

  // 设置部分2的策略
  setStrategyForPart2(strategy: Strategy): void {
    this.strategyForPart2 = strategy;
  }

  // 执行策略
  execute(): void {
    if (this.strategyForPart1 && this.strategyForPart2) {
      this.strategyForPart1.execute();
      // 部分1的逻辑...
      this.strategyForPart2.execute();
      // 部分2的逻辑...
    } else {
      console.log("Strategies for both parts are required.");
    }
  }
}

// 使用策略设计模式
const context = new Context();
// 设置部分1的策略为策略A
context.setStrategyForPart1(new ConcreteStrategyA());
// 设置部分2的策略为策略B
context.setStrategyForPart2(new ConcreteStrategyB());
// 执行策略
context.execute();

应用场景

1.\color{blue}{1.} 数据格式化:根据不同的数据类型和格式要求,使用不同的格式化策略,如日期格式化、数字格式化、货币格式化等。

2.\color{blue}{2.} 缓存策略:根据不同的缓存需求,使用不同的缓存策略,如内存缓存、本地存储缓存、服务端缓存等。

3.\color{blue}{3.} 表单验证:根据不同的表单输入类型和验证规则,使用不同的验证策略,如文本输入、数字输入、邮箱输入等。

4.\color{blue}{4.} 图片加载策略:根据不同的图片加载需求,使用不同的加载策略,如立即加载、懒加载、按需加载等。