策略模式
约 671 字
策略模式
核心思想
策略模式允许定义一系列的算法,并将每种算法放入独立的类中,以使算法对象能够相互替换。
典型用例
会员定价策略
在付费平台会依据不同等级的会员来制定不同的定价策略,例如: 一般用户无折扣、普通会员享有九折、高级会员享有八折。
在这个例子中,购物车计算折扣的方式取决于它使用的策略,通过改变策略,可以改变折扣的计算方式,而不需要修改购物车本身。
// npm run code src/code/design-pattern/strategy/member-pricing.ts
export {};
// 定义一个策略接口,用于所有具体策略的共同行为
interface DiscountStrategy {
calculateDiscount(amount: number): number;
}
// 为不同类型的用户创建具体的策略类,每个类都实现抽象的策略接口
class RegularUserDiscount implements DiscountStrategy {
calculateDiscount(amount: number): number {
// 普通用户可能没有折扣
return amount;
}
}
class MemberUserDiscount implements DiscountStrategy {
calculateDiscount(amount: number): number {
// 会员用户享受一定的折扣
return amount * 0.9; // 假设会员用户享有10%的折扣
}
}
class PremiumMemberDiscount implements DiscountStrategy {
calculateDiscount(amount: number): number {
// 高级会员用户享受更高的折扣
return amount * 0.8; // 假设高级会员享有20%的折扣
}
}
// 创建一个上下文,用于管理策略,并根据策略计算出折扣价
class ShoppingCart {
private strategy: DiscountStrategy;
constructor(strategy: DiscountStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: DiscountStrategy): void {
this.strategy = strategy;
}
calculateDiscountedTotal(amount: number): number {
return this.strategy.calculateDiscount(amount);
}
}
const regularCart = new ShoppingCart(new RegularUserDiscount());
console.log(regularCart.calculateDiscountedTotal(100)); // 输出 100
const memberCart = new ShoppingCart(new MemberUserDiscount());
console.log(memberCart.calculateDiscountedTotal(100)); // 输出 90
const premiumCart = new ShoppingCart(new PremiumMemberDiscount());
console.log(premiumCart.calculateDiscountedTotal(100)); // 输出 80
排序和搜索
在数据处理应用中,策略模式可以根据不同的数据集或性能要求选择不同的排序或搜索算法。例如,对小数据集使用插入排序,而对大数据集使用快速排序。
// npm run code src/code/design-pattern/strategy/sort-and-search.ts
export {};
// 排序策略接口
interface SortStrategy {
sort(data: number[]): number[];
}
// 插入排序策略
class InsertionSortStrategy implements SortStrategy {
sort(data: number[]): number[] {
// 插入排序的实现
console.log("Using Insertion Sort");
// ...排序逻辑
return data;
}
}
// 快速排序策略
class QuickSortStrategy implements SortStrategy {
sort(data: number[]): number[] {
// 快速排序的实现
console.log("Using Quick Sort");
// ...排序逻辑
return data;
}
}
// 上下文类
class SortContext {
private strategy: SortStrategy;
constructor(strategy: SortStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: SortStrategy) {
this.strategy = strategy;
}
sortData(data: number[]): number[] {
return this.strategy.sort(data);
}
}
// 示例使用
const smallDataSet = [2, 3, 1];
const largeDataSet = [2, 3, 1, 5, 4, 7, 6, 9, 8];
const context = new SortContext(new InsertionSortStrategy());
console.log("Sorting small data set:");
context.sortData(smallDataSet);
// 更改策略用于大数据集
context.setStrategy(new QuickSortStrategy());
console.log("Sorting large data set:");
context.sortData(largeDataSet);
导航和路由选择
策略模式可以用于选择不同的导航和路线。
// npm run code src/code/design-pattern/strategy/navigation.ts
export {};
// 路线规划策略接口
interface RouteStrategy {
planRoute(startPoint: string, endPoint: string): string;
}
// 最短路线策略
class ShortestRouteStrategy implements RouteStrategy {
planRoute(startPoint: string, endPoint: string): string {
return `Planning the shortest route from ${startPoint} to ${endPoint}`;
}
}
// 避开拥堵路线策略
class AvoidTrafficRouteStrategy implements RouteStrategy {
planRoute(startPoint: string, endPoint: string): string {
return `Planning a route from ${startPoint} to ${endPoint} that avoids traffic`;
}
}
// 最节能路线策略
class EcoFriendlyRouteStrategy implements RouteStrategy {
planRoute(startPoint: string, endPoint: string): string {
return `Planning an eco-friendly route from ${startPoint} to ${endPoint}`;
}
}
// 导航上下文类
class NavigationContext {
private strategy: RouteStrategy;
constructor(strategy: RouteStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: RouteStrategy) {
this.strategy = strategy;
}
planRoute(startPoint: string, endPoint: string): string {
return this.strategy.planRoute(startPoint, endPoint);
}
}
// 示例使用
const navigation = new NavigationContext(new ShortestRouteStrategy());
console.log(navigation.planRoute("Home", "Office"));
// 更改策略为避开拥堵
navigation.setStrategy(new AvoidTrafficRouteStrategy());
console.log(navigation.planRoute("Home", "Office"));
// 更改策略为最节能
navigation.setStrategy(new EcoFriendlyRouteStrategy());
console.log(navigation.planRoute("Home", "Office"));
数据压缩和加密
在需要对数据进行压缩或加密的应用中,策略模式可以根据不同的场景或需求选择不同的压缩或加密算法。在这个例子中,定义了一个策略接口,然后实现几个具体的策略:一种是用于数据压缩的策略,另一种是用于数据加密的策略。最后,创建一个上下文类来根据不同的需求使用这些策略。
// npm run code src/code/design-pattern/strategy/data-compression-and-encryption.ts
export {};
// 数据处理策略接口
interface DataStrategy {
processData(data: string): string;
}
// 压缩策略
class CompressionStrategy implements DataStrategy {
processData(data: string): string {
// 这里只是一个示意,实际压缩逻辑会更复杂
return `Compressed data: ${data}`;
}
}
// 加密策略
class EncryptionStrategy implements DataStrategy {
processData(data: string): string {
// 这里只是一个示意,实际加密逻辑会更复杂
return `Encrypted data: ${data}`;
}
}
// 数据处理上下文类
class DataContext {
private strategy: DataStrategy;
constructor(strategy: DataStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: DataStrategy) {
this.strategy = strategy;
}
process(data: string): string {
return this.strategy.processData(data);
}
}
// 示例使用
const dataContext = new DataContext(new CompressionStrategy());
console.log(dataContext.process("Example data"));
// 更改策略为加密
dataContext.setStrategy(new EncryptionStrategy());
console.log(dataContext.process("Example data"));
日志记录
策略模式适合用于实现灵活的日志记录机制。在这个例子中,定义一个日志策略接口,然后为记录到文件、数据库和通过网络发送实现不同的策略。最后,创建一个上下文类来使用这些策略,根据当前的上下文或配置选择合适的日志记录方法。
// npm run code src/code/design-pattern/strategy/log-recording.ts
export {};
// 日志策略接口
interface LogStrategy {
log(message: string): void;
}
// 文件日志策略
class FileLogStrategy implements LogStrategy {
log(message: string): void {
console.log(`Writing to file: ${message}`);
// 实际文件写入逻辑
}
}
// 数据库日志策略
class DatabaseLogStrategy implements LogStrategy {
log(message: string): void {
console.log(`Saving to database: ${message}`);
// 实际数据库保存逻辑
}
}
// 网络日志策略
class NetworkLogStrategy implements LogStrategy {
log(message: string): void {
console.log(`Sending over network: ${message}`);
// 实际网络发送逻辑
}
}
// 日志上下文类
class Logger {
private strategy: LogStrategy;
constructor(strategy: LogStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: LogStrategy) {
this.strategy = strategy;
}
log(message: string): void {
this.strategy.log(message);
}
}
// 示例使用
const logger = new Logger(new FileLogStrategy());
logger.log("File log example");
// 更改策略为数据库日志
logger.setStrategy(new DatabaseLogStrategy());
logger.log("Database log example");
// 更改策略为网络日志
logger.setStrategy(new NetworkLogStrategy());
logger.log("Network log example");
用户界面渲染
策略模式可以用来处理不同的用户界面UI渲染策略。在这个例子中,定义一个UI渲染策略接口,并为不同的用户偏好或设备特性实现具体的策略,比如简洁版UI或高互动版UI。最后,创建一个上下文类来根据用户偏好或设备特性选择相应的渲染策略。
// npm run code src/code/design-pattern/strategy/user-interface-rendering.ts
export {};
// UI渲染策略接口
interface UIRenderStrategy {
render(): string;
}
// 简洁版UI策略
class SimpleUIRenderStrategy implements UIRenderStrategy {
render(): string {
return "Rendering Simple UI";
}
}
// 高互动版UI策略
class InteractiveUIRenderStrategy implements UIRenderStrategy {
render(): string {
return "Rendering Interactive UI";
}
}
// UI上下文类
class UIContext {
private strategy: UIRenderStrategy;
constructor(strategy: UIRenderStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: UIRenderStrategy) {
this.strategy = strategy;
}
renderUI(): string {
return this.strategy.render();
}
}
// 示例使用
const userPreference = 'interactive'; // 假设这是从用户配置中获得的
const uiContext = new UIContext(
userPreference === 'interactive' ? new InteractiveUIRenderStrategy() : new SimpleUIRenderStrategy()
);
console.log(uiContext.renderUI());