策略模式详解:概念、实现与应用
引言
策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,使算法的变化独立于使用它们的客户端。
什么是策略模式?
策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,使算法的变化独立于使用它们的客户端。策略模式让算法的变化独立于使用算法的客户。
核心思想
策略模式的核心思想是:
- 算法封装:将不同的算法封装在独立的类中
- 统一接口:为所有算法提供统一的接口
- 动态切换:允许在运行时选择和切换算法
为什么需要策略模式?
在许多情况下,我们需要在不同的算法之间进行选择:
1. 算法多样性
当需要实现多种算法来解决同一问题时:
- 排序算法(快速排序、归并排序、堆排序)
- 路径查找算法(Dijkstra、A*、BFS)
- 压缩算法(ZIP、RAR、7Z)
2. 算法可替换性
当需要在运行时动态选择算法时:
- 根据输入数据特征选择最优算法
- 根据系统配置选择合适算法
- 根据用户偏好切换算法
3. 避免条件语句
当需要避免大量的条件判断语句时:
- 减少 if-else 或 switch-case 语句
- 提高代码的可维护性
- 增强系统的可扩展性
策略模式的基本实现
让我们从一个简单的策略模式实现开始:
javascript
// 策略接口
class Strategy {
execute(data) {
throw new Error('必须实现 execute 方法');
}
}
// 具体策略 A
class ConcreteStrategyA extends Strategy {
execute(data) {
return `具体策略A处理数据: ${data.toUpperCase()}`;
}
}
// 具体策略 B
class ConcreteStrategyB extends Strategy {
execute(data) {
return `具体策略B处理数据: ${data.toLowerCase()}`;
}
}
// 具体策略 C
class ConcreteStrategyC extends Strategy {
execute(data) {
return `具体策略C处理数据: ${data.split('').reverse().join('')}`;
}
}
// 上下文
class Context {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
executeStrategy(data) {
return this.strategy.execute(data);
}
}
// 客户端代码
function clientCode() {
const context = new Context(new ConcreteStrategyA());
console.log('客户端: 使用策略A');
console.log(context.executeStrategy('Hello World'));
console.log('客户端: 切换到策略B');
context.setStrategy(new ConcreteStrategyB());
console.log(context.executeStrategy('Hello World'));
console.log('客户端: 切换到策略C');
context.setStrategy(new ConcreteStrategyC());
console.log(context.executeStrategy('Hello World'));
}
clientCode();实现要点分析
- 策略接口:定义所有策略的公共接口
- 具体策略:实现具体的算法
- 上下文:使用策略的类,维护对策略的引用
- 客户端:创建上下文并配置具体策略
- 动态切换:支持在运行时切换策略
策略模式的实际应用场景
1. 排序算法选择
在数据处理中,策略模式非常适合用于实现不同的排序算法:
javascript
// 排序策略接口
class SortStrategy {
sort(data) {
throw new Error('必须实现 sort 方法');
}
getName() {
throw new Error('必须实现 getName 方法');
}
}
// 冒泡排序策略
class BubbleSortStrategy extends SortStrategy {
sort(data) {
console.log('使用冒泡排序');
const arr = [...data]; // 创建副本,避免修改原数组
const n = arr.length;
for (let i = 0; i < n - 1; i++) {
for (let j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换元素
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr;
}
getName() {
return '冒泡排序';
}
}
// 快速排序策略
class QuickSortStrategy extends SortStrategy {
sort(data) {
console.log('使用快速排序');
const arr = [...data];
return this.quickSort(arr, 0, arr.length - 1);
}
quickSort(arr, low, high) {
if (low < high) {
const pi = this.partition(arr, low, high);
this.quickSort(arr, low, pi - 1);
this.quickSort(arr, pi + 1, high);
}
return arr;
}
partition(arr, low, high) {
const pivot = arr[high];
let i = low - 1;
for (let j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
return i + 1;
}
getName() {
return '快速排序';
}
}
// 归并排序策略
class MergeSortStrategy extends SortStrategy {
sort(data) {
console.log('使用归并排序');
const arr = [...data];
return this.mergeSort(arr);
}
mergeSort(arr) {
if (arr.length <= 1) {
return arr;
}
const mid = Math.floor(arr.length / 2);
const left = arr.slice(0, mid);
const right = arr.slice(mid);
return this.merge(this.mergeSort(left), this.mergeSort(right));
}
merge(left, right) {
const result = [];
let leftIndex = 0;
let rightIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
if (left[leftIndex] < right[rightIndex]) {
result.push(left[leftIndex]);
leftIndex++;
} else {
result.push(right[rightIndex]);
rightIndex++;
}
}
return result
.concat(left.slice(leftIndex))
.concat(right.slice(rightIndex));
}
getName() {
return '归并排序';
}
}
// 堆排序策略
class HeapSortStrategy extends SortStrategy {
sort(data) {
console.log('使用堆排序');
const arr = [...data];
const n = arr.length;
// 构建最大堆
for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {
this.heapify(arr, n, i);
}
// 逐个从堆顶取出元素
for (let i = n - 1; i > 0; i--) {
[arr[0], arr[i]] = [arr[i], arr[0]];
this.heapify(arr, i, 0);
}
return arr;
}
heapify(arr, n, i) {
let largest = i;
const left = 2 * i + 1;
const right = 2 * i + 2;
if (left < n && arr[left] > arr[largest]) {
largest = left;
}
if (right < n && arr[right] > arr[largest]) {
largest = right;
}
if (largest !== i) {
[arr[i], arr[largest]] = [arr[largest], arr[i]];
this.heapify(arr, n, largest);
}
}
getName() {
return '堆排序';
}
}
// 排序上下文
class SortContext {
constructor(strategy = null) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
sort(data) {
if (!this.strategy) {
throw new Error('未设置排序策略');
}
console.log(`排序上下文: 使用 ${this.strategy.getName()}`);
const startTime = performance.now();
const result = this.strategy.sort(data);
const endTime = performance.now();
console.log(`排序耗时: ${(endTime - startTime).toFixed(2)}ms`);
return result;
}
// 根据数据特征自动选择最优策略
autoSort(data) {
let strategy;
if (data.length < 10) {
strategy = new BubbleSortStrategy();
} else if (data.length < 1000) {
strategy = new QuickSortStrategy();
} else {
strategy = new MergeSortStrategy();
}
this.setStrategy(strategy);
return this.sort(data);
}
}
// 排序性能测试器
class SortPerformanceTester {
constructor() {
this.context = new SortContext();
}
testStrategy(strategy, data, name) {
this.context.setStrategy(strategy);
console.log(`\n=== 测试 ${name} ===`);
return this.context.sort(data);
}
compareStrategies(data) {
console.log('=== 排序算法性能比较 ===');
const strategies = [
new BubbleSortStrategy(),
new QuickSortStrategy(),
new MergeSortStrategy(),
new HeapSortStrategy()
];
const results = [];
for (const strategy of strategies) {
const testData = [...data];
const startTime = performance.now();
strategy.sort(testData);
const endTime = performance.now();
results.push({
name: strategy.getName(),
time: endTime - startTime
});
}
// 按性能排序
results.sort((a, b) => a.time - b.time);
console.log('\n性能排名:');
results.forEach((result, index) => {
console.log(`${index + 1}. ${result.name}: ${result.time.toFixed(2)}ms`);
});
return results;
}
}
// 使用示例
function sortingExample() {
const sorter = new SortContext();
const tester = new SortPerformanceTester();
console.log('=== 排序策略示例 ===');
// 测试数据
const smallData = [64, 34, 25, 12, 22, 11, 90];
const largeData = Array.from({length: 1000}, () => Math.floor(Math.random() * 1000));
console.log('原始小数据:', smallData);
// 使用不同策略排序
sorter.setStrategy(new BubbleSortStrategy());
console.log('冒泡排序结果:', sorter.sort(smallData));
sorter.setStrategy(new QuickSortStrategy());
console.log('快速排序结果:', sorter.sort(smallData));
sorter.setStrategy(new MergeSortStrategy());
console.log('归并排序结果:', sorter.sort(smallData));
console.log('\n=== 自动选择策略 ===');
console.log('自动排序小数据:', sorter.autoSort(smallData));
console.log('自动排序大数据:', sorter.autoSort(largeData.slice(0, 50)));
console.log('\n=== 性能比较 ===');
tester.compareStrategies(Array.from({length: 100}, () => Math.floor(Math.random() * 100)));
}
sortingExample();2. 支付方式选择
在电商系统中,策略模式非常适合用于实现不同的支付方式:
javascript
// 支付策略接口
class PaymentStrategy {
pay(amount) {
throw new Error('必须实现 pay 方法');
}
getName() {
throw new Error('必须实现 getName 方法');
}
validatePaymentInfo(paymentInfo) {
throw new Error('必须实现 validatePaymentInfo 方法');
}
}
// 信用卡支付策略
class CreditCardPaymentStrategy extends PaymentStrategy {
constructor(cardNumber, expiryDate, cvv) {
super();
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
this.cvv = cvv;
}
pay(amount) {
if (!this.validatePaymentInfo()) {
throw new Error('信用卡信息验证失败');
}
console.log(`信用卡支付: 使用卡号 ${this.maskCardNumber()} 支付 $${amount}`);
// 模拟支付处理
return {
success: true,
transactionId: `CC_${Date.now()}`,
message: '信用卡支付成功'
};
}
getName() {
return '信用卡支付';
}
validatePaymentInfo() {
// 简单的验证逻辑
return this.cardNumber && this.expiryDate && this.cvv &&
this.cardNumber.length >= 15 &&
this.cvv.length === 3;
}
maskCardNumber() {
if (!this.cardNumber) return '';
return '*'.repeat(this.cardNumber.length - 4) + this.cardNumber.slice(-4);
}
}
// 支付宝支付策略
class AlipayPaymentStrategy extends PaymentStrategy {
constructor(account) {
super();
this.account = account;
}
pay(amount) {
if (!this.validatePaymentInfo()) {
throw new Error('支付宝账户验证失败');
}
console.log(`支付宝支付: 使用账户 ${this.account} 支付 ¥${amount}`);
// 模拟支付处理
return {
success: true,
transactionId: `ALIPAY_${Date.now()}`,
message: '支付宝支付成功',
qrCode: `alipay://pay?amount=${amount}&account=${this.account}`
};
}
getName() {
return '支付宝支付';
}
validatePaymentInfo() {
// 简单的验证逻辑
return this.account && this.account.includes('@');
}
}
// 微信支付策略
class WeChatPayPaymentStrategy extends PaymentStrategy {
constructor(openId) {
super();
this.openId = openId;
}
pay(amount) {
if (!this.validatePaymentInfo()) {
throw new Error('微信账户验证失败');
}
console.log(`微信支付: 使用OpenID ${this.openId} 支付 ¥${amount}`);
// 模拟支付处理
return {
success: true,
transactionId: `WECHAT_${Date.now()}`,
message: '微信支付成功',
qrCode: `wechat://pay?amount=${amount}&openid=${this.openId}`
};
}
getName() {
return '微信支付';
}
validatePaymentInfo() {
// 简单的验证逻辑
return this.openId && this.openId.length > 10;
}
}
// PayPal支付策略
class PayPalPaymentStrategy extends PaymentStrategy {
constructor(email) {
super();
this.email = email;
}
pay(amount) {
if (!this.validatePaymentInfo()) {
throw new Error('PayPal账户验证失败');
}
console.log(`PayPal支付: 使用邮箱 ${this.email} 支付 $${amount}`);
// 模拟支付处理
return {
success: true,
transactionId: `PAYPAL_${Date.now()}`,
message: 'PayPal支付成功',
redirectUrl: `https://paypal.com/pay?amount=${amount}&email=${this.email}`
};
}
getName() {
return 'PayPal支付';
}
validatePaymentInfo() {
// 简单的验证逻辑
return this.email && this.email.includes('@') && this.email.includes('.');
}
}
// 现金支付策略
class CashPaymentStrategy extends PaymentStrategy {
pay(amount) {
console.log(`现金支付: 收到现金 $${amount}`);
// 模拟支付处理
return {
success: true,
transactionId: `CASH_${Date.now()}`,
message: '现金支付成功',
change: 0
};
}
getName() {
return '现金支付';
}
validatePaymentInfo() {
return true; // 现金支付无需验证
}
}
// 支付上下文
class PaymentContext {
constructor(strategy = null) {
this.strategy = strategy;
this.transactionHistory = [];
}
setStrategy(strategy) {
this.strategy = strategy;
}
executePayment(amount, paymentInfo = null) {
if (!this.strategy) {
throw new Error('未设置支付策略');
}
console.log(`支付上下文: 使用 ${this.strategy.getName()} 进行支付`);
try {
const result = this.strategy.pay(amount);
if (result.success) {
this.transactionHistory.push({
strategy: this.strategy.getName(),
amount: amount,
transactionId: result.transactionId,
timestamp: new Date(),
...result
});
console.log(`支付成功: ${result.message}`);
return result;
} else {
throw new Error(result.message || '支付失败');
}
} catch (error) {
console.error(`支付失败: ${error.message}`);
throw error;
}
}
getTransactionHistory() {
return [...this.transactionHistory];
}
getTotalAmount() {
return this.transactionHistory.reduce((total, transaction) => total + transaction.amount, 0);
}
// 根据支付金额自动选择策略
autoPay(amount, preferredMethod = null) {
let strategy;
// 根据金额和偏好选择策略
if (amount <= 0) {
throw new Error('支付金额必须大于0');
}
if (preferredMethod) {
strategy = this.createStrategyByMethod(preferredMethod);
} else if (amount < 1) {
strategy = new CashPaymentStrategy();
} else if (amount < 100) {
strategy = new WeChatPayPaymentStrategy('openid_12345');
} else {
strategy = new CreditCardPaymentStrategy('1234567890123456', '12/25', '123');
}
this.setStrategy(strategy);
return this.executePayment(amount);
}
createStrategyByMethod(method, paymentInfo = {}) {
switch (method.toLowerCase()) {
case 'creditcard':
return new CreditCardPaymentStrategy(
paymentInfo.cardNumber || '1234567890123456',
paymentInfo.expiryDate || '12/25',
paymentInfo.cvv || '123'
);
case 'alipay':
return new AlipayPaymentStrategy(paymentInfo.account || 'user@example.com');
case 'wechat':
return new WeChatPayPaymentStrategy(paymentInfo.openId || 'openid_12345');
case 'paypal':
return new PayPalPaymentStrategy(paymentInfo.email || 'user@example.com');
case 'cash':
return new CashPaymentStrategy();
default:
throw new Error(`不支持的支付方式: ${method}`);
}
}
}
// 支付管理器
class PaymentManager {
constructor() {
this.context = new PaymentContext();
}
processPayment(amount, method, paymentInfo = {}) {
try {
const strategy = this.context.createStrategyByMethod(method, paymentInfo);
this.context.setStrategy(strategy);
return this.context.executePayment(amount, paymentInfo);
} catch (error) {
console.error(`支付处理失败: ${error.message}`);
throw error;
}
}
getPaymentStatistics() {
const history = this.context.getTransactionHistory();
const stats = {
totalTransactions: history.length,
totalAmount: this.context.getTotalAmount(),
paymentMethods: {}
};
// 统计各支付方式的使用情况
for (const transaction of history) {
const method = transaction.strategy;
if (!stats.paymentMethods[method]) {
stats.paymentMethods[method] = { count: 0, amount: 0 };
}
stats.paymentMethods[method].count++;
stats.paymentMethods[method].amount += transaction.amount;
}
return stats;
}
refund(transactionId, amount) {
const history = this.context.getTransactionHistory();
const transaction = history.find(t => t.transactionId === transactionId);
if (!transaction) {
throw new Error(`未找到交易记录: ${transactionId}`);
}
if (amount > transaction.amount) {
throw new Error('退款金额不能超过原交易金额');
}
console.log(`退款: 交易 ${transactionId} 退款 $${amount}`);
return {
success: true,
refundId: `REFUND_${Date.now()}`,
message: '退款成功'
};
}
}
// 使用示例
function paymentExample() {
const paymentManager = new PaymentManager();
console.log('=== 支付策略示例 ===');
try {
// 信用卡支付
console.log('\n=== 信用卡支付 ===');
const creditCardResult = paymentManager.processPayment(100, 'creditcard', {
cardNumber: '1234567890123456',
expiryDate: '12/25',
cvv: '123'
});
console.log('支付结果:', creditCardResult);
// 支付宝支付
console.log('\n=== 支付宝支付 ===');
const alipayResult = paymentManager.processPayment(50, 'alipay', {
account: 'user@example.com'
});
console.log('支付结果:', alipayResult);
// 微信支付
console.log('\n=== 微信支付 ===');
const wechatResult = paymentManager.processPayment(30, 'wechat', {
openId: 'openid_12345'
});
console.log('支付结果:', wechatResult);
// PayPal支付
console.log('\n=== PayPal支付 ===');
const paypalResult = paymentManager.processPayment(75, 'paypal', {
email: 'user@example.com'
});
console.log('支付结果:', paypalResult);
// 现金支付
console.log('\n=== 现金支付 ===');
const cashResult = paymentManager.processPayment(5, 'cash');
console.log('支付结果:', cashResult);
console.log('\n=== 自动支付选择 ===');
const autoResult1 = paymentManager.context.autoPay(0.5); // 现金
console.log('小额支付:', autoResult1);
const autoResult2 = paymentManager.context.autoPay(50); // 微信
console.log('中额支付:', autoResult2);
const autoResult3 = paymentManager.context.autoPay(500); // 信用卡
console.log('大额支付:', autoResult3);
console.log('\n=== 交易统计 ===');
const stats = paymentManager.getPaymentStatistics();
console.log('统计信息:', JSON.stringify(stats, null, 2));
console.log('\n=== 退款处理 ===');
const refundResult = paymentManager.refund(creditCardResult.transactionId, 50);
console.log('退款结果:', refundResult);
} catch (error) {
console.error('支付示例出错:', error.message);
}
}
// 运行示例
paymentExample();3. 路径规划算法
在导航系统中,策略模式非常适合用于实现不同的路径规划算法:
javascript
// 路径规划策略接口
class RouteStrategy {
calculateRoute(start, end, options = {}) {
throw new Error('必须实现 calculateRoute 方法');
}
getName() {
throw new Error('必须实现 getName 方法');
}
getEstimatedTime(distance, options = {}) {
throw new Error('必须实现 getEstimatedTime 方法');
}
}
// 最短距离策略
class ShortestDistanceStrategy extends RouteStrategy {
calculateRoute(start, end, options = {}) {
console.log('使用最短距离算法计算路径');
// 模拟路径计算
const distance = this.calculateDistance(start, end);
const time = this.getEstimatedTime(distance, options);
const route = this.generateRoute(start, end);
return {
strategy: this.getName(),
route: route,
distance: distance,
estimatedTime: time,
details: '选择最短路径,可能涉及较多红绿灯'
};
}
getName() {
return '最短距离';
}
calculateDistance(start, end) {
// 简化的距离计算(欧几里得距离)
const dx = end.x - start.x;
const dy = end.y - start.y;
return Math.sqrt(dx * dx + dy * dy);
}
getEstimatedTime(distance, options = {}) {
const speed = options.speed || 40; // 默认40公里/小时
return (distance / speed) * 60; // 返回分钟
}
generateRoute(start, end) {
// 简化的路径生成
return [
{ x: start.x, y: start.y, name: '起点' },
{ x: (start.x + end.x) / 2, y: (start.y + end.y) / 2, name: '中点' },
{ x: end.x, y: end.y, name: '终点' }
];
}
}
// 最快速度策略
class FastestRouteStrategy extends RouteStrategy {
calculateRoute(start, end, options = {}) {
console.log('使用最快速度算法计算路径');
// 模拟路径计算(考虑道路限速)
const distance = this.calculateDistance(start, end);
const time = this.getEstimatedTime(distance, options);
const route = this.generateRoute(start, end);
return {
strategy: this.getName(),
route: route,
distance: distance,
estimatedTime: time,
details: '优先选择高速公路,避免红绿灯'
};
}
getName() {
return '最快速度';
}
calculateDistance(start, end) {
// 考虑实际道路距离
const directDistance = Math.sqrt(
Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)
);
return directDistance * 1.2; // 实际道路距离通常更长
}
getEstimatedTime(distance, options = {}) {
const speed = options.speed || 60; // 高速公路默认60公里/小时
return (distance / speed) * 60;
}
generateRoute(start, end) {
// 优先选择高速公路
return [
{ x: start.x, y: start.y, name: '起点' },
{ x: start.x + 5, y: start.y + 5, name: '高速公路入口' },
{ x: end.x - 5, y: end.y - 5, name: '高速公路出口' },
{ x: end.x, y: end.y, name: '终点' }
];
}
}
// 最少收费策略
class LeastTollStrategy extends RouteStrategy {
calculateRoute(start, end, options = {}) {
console.log('使用最少收费算法计算路径');
const distance = this.calculateDistance(start, end);
const time = this.getEstimatedTime(distance, options);
const route = this.generateRoute(start, end);
const toll = this.calculateToll(route);
return {
strategy: this.getName(),
route: route,
distance: distance,
estimatedTime: time,
toll: toll,
details: '避免收费道路,可能增加行驶时间'
};
}
getName() {
return '最少收费';
}
calculateDistance(start, end) {
const directDistance = Math.sqrt(
Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)
);
return directDistance * 1.3; // 避开收费道路可能更绕远
}
getEstimatedTime(distance, options = {}) {
const speed = options.speed || 35; // 普通道路默认35公里/小时
return (distance / speed) * 60;
}
generateRoute(start, end) {
// 避开收费道路
return [
{ x: start.x, y: start.y, name: '起点' },
{ x: start.x + 2, y: start.y + 8, name: '省道1号' },
{ x: end.x - 2, y: end.y - 8, name: '省道2号' },
{ x: end.x, y: end.y, name: '终点' }
];
}
calculateToll(route) {
// 计算过路费(假设有部分路段收费)
return route.length > 3 ? 15.5 : 0;
}
}
// 步行路径策略
class WalkingRouteStrategy extends RouteStrategy {
calculateRoute(start, end, options = {}) {
console.log('使用步行路径算法计算路径');
const distance = this.calculateDistance(start, end);
const time = this.getEstimatedTime(distance, options);
const route = this.generateRoute(start, end);
return {
strategy: this.getName(),
route: route,
distance: distance,
estimatedTime: time,
details: '适合步行的路径,避开高速公路'
};
}
getName() {
return '步行路径';
}
calculateDistance(start, end) {
const directDistance = Math.sqrt(
Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)
);
return directDistance;
}
getEstimatedTime(distance, options = {}) {
const speed = options.speed || 5; // 步行默认5公里/小时
return (distance / speed) * 60;
}
generateRoute(start, end) {
// 生成适合步行的路径
return [
{ x: start.x, y: start.y, name: '起点' },
{ x: start.x + 1, y: start.y + 1, name: '人行道1' },
{ x: start.x + 2, y: start.y + 2, name: '公园路径' },
{ x: end.x - 1, y: end.y - 1, name: '人行道2' },
{ x: end.x, y: end.y, name: '终点' }
];
}
}
// 骑行路径策略
class CyclingRouteStrategy extends RouteStrategy {
calculateRoute(start, end, options = {}) {
console.log('使用骑行路径算法计算路径');
const distance = this.calculateDistance(start, end);
const time = this.getEstimatedTime(distance, options);
const route = this.generateRoute(start, end);
return {
strategy: this.getName(),
route: route,
distance: distance,
estimatedTime: time,
details: '自行车友好路径,避开高速公路和复杂路段'
};
}
getName() {
return '骑行路径';
}
calculateDistance(start, end) {
const directDistance = Math.sqrt(
Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)
);
return directDistance * 1.1; // 骑行路径可能稍长
}
getEstimatedTime(distance, options = {}) {
const speed = options.speed || 15; // 骑行默认15公里/小时
return (distance / speed) * 60;
}
generateRoute(start, end) {
// 生成自行车友好路径
return [
{ x: start.x, y: start.y, name: '起点' },
{ x: start.x + 3, y: start.y + 1, name: '自行车道1' },
{ x: start.x + 6, y: start.y + 2, name: '绿道' },
{ x: end.x - 3, y: end.y - 1, name: '自行车道2' },
{ x: end.x, y: end.y, name: '终点' }
];
}
}
// 路径规划上下文
class RouteContext {
constructor(strategy = null) {
this.strategy = strategy;
this.routeHistory = [];
}
setStrategy(strategy) {
this.strategy = strategy;
}
calculateRoute(start, end, options = {}) {
if (!this.strategy) {
throw new Error('未设置路径规划策略');
}
console.log(`路径规划上下文: 使用 ${this.strategy.getName()} 算法`);
const result = this.strategy.calculateRoute(start, end, options);
this.routeHistory.push({
...result,
start: start,
end: end,
timestamp: new Date()
});
return result;
}
getRouteHistory() {
return [...this.routeHistory];
}
// 根据出行方式自动选择策略
autoPlanRoute(start, end, travelMode, options = {}) {
let strategy;
switch (travelMode.toLowerCase()) {
case 'driving':
strategy = new FastestRouteStrategy();
break;
case 'walking':
strategy = new WalkingRouteStrategy();
break;
case 'cycling':
strategy = new CyclingRouteStrategy();
break;
default:
strategy = new FastestRouteStrategy();
}
this.setStrategy(strategy);
return this.calculateRoute(start, end, options);
}
// 比较不同策略的结果
compareRoutes(start, end, options = {}) {
const strategies = [
new ShortestDistanceStrategy(),
new FastestRouteStrategy(),
new LeastTollStrategy(),
new WalkingRouteStrategy(),
new CyclingRouteStrategy()
];
const results = [];
for (const strategy of strategies) {
this.setStrategy(strategy);
try {
const result = this.calculateRoute(start, end, options);
results.push(result);
} catch (error) {
console.error(`策略 ${strategy.getName()} 执行失败:`, error.message);
}
}
return results;
}
}
// 导航系统
class NavigationSystem {
constructor() {
this.context = new RouteContext();
}
planRoute(start, end, strategyName, options = {}) {
let strategy;
switch (strategyName.toLowerCase()) {
case 'shortest':
strategy = new ShortestDistanceStrategy();
break;
case 'fastest':
strategy = new FastestRouteStrategy();
break;
case 'leasttoll':
strategy = new LeastTollStrategy();
break;
case 'walking':
strategy = new WalkingRouteStrategy();
break;
case 'cycling':
strategy = new CyclingRouteStrategy();
break;
default:
throw new Error(`不支持的路径规划策略: ${strategyName}`);
}
this.context.setStrategy(strategy);
return this.context.calculateRoute(start, end, options);
}
getRouteRecommendation(start, end, preferences = {}) {
console.log('=== 路径规划建议 ===');
const results = this.context.compareRoutes(start, end, preferences);
// 根据偏好排序结果
results.sort((a, b) => {
// 如果用户偏好最快路径
if (preferences.priority === 'time') {
return a.estimatedTime - b.estimatedTime;
}
// 如果用户偏好最短路径
else if (preferences.priority === 'distance') {
return a.distance - b.distance;
}
// 默认按时间排序
else {
return a.estimatedTime - b.estimatedTime;
}
});
return results;
}
getNavigationStats() {
const history = this.context.getRouteHistory();
const stats = {
totalRoutes: history.length,
totalDistance: history.reduce((sum, route) => sum + route.distance, 0),
strategiesUsed: {}
};
// 统计各策略的使用情况
for (const route of history) {
const strategy = route.strategy;
if (!stats.strategiesUsed[strategy]) {
stats.strategiesUsed[strategy] = 0;
}
stats.strategiesUsed[strategy]++;
}
return stats;
}
}
// 使用示例
function navigationExample() {
const navigation = new NavigationSystem();
console.log('=== 路径规划策略示例 ===');
const start = { x: 0, y: 0, name: '当前位置' };
const end = { x: 20, y: 20, name: '目的地' };
try {
// 最短距离路径
console.log('\n=== 最短距离路径 ===');
const shortestRoute = navigation.planRoute(start, end, 'shortest');
console.log('路径信息:', JSON.stringify(shortestRoute, null, 2));
// 最快速度路径
console.log('\n=== 最快速度路径 ===');
const fastestRoute = navigation.planRoute(start, end, 'fastest');
console.log('路径信息:', JSON.stringify(fastestRoute, null, 2));
// 最少收费路径
console.log('\n=== 最少收费路径 ===');
const leastTollRoute = navigation.planRoute(start, end, 'leasttoll');
console.log('路径信息:', JSON.stringify(leastTollRoute, null, 2));
// 步行路径
console.log('\n=== 步行路径 ===');
const walkingRoute = navigation.planRoute(start, end, 'walking');
console.log('路径信息:', JSON.stringify(walkingRoute, null, 2));
// 骑行路径
console.log('\n=== 骑行路径 ===');
const cyclingRoute = navigation.planRoute(start, end, 'cycling');
console.log('路径信息:', JSON.stringify(cyclingRoute, null, 2));
console.log('\n=== 路径建议 ===');
const recommendations = navigation.getRouteRecommendation(start, end, { priority: 'time' });
console.log('推荐路径:');
recommendations.slice(0, 3).forEach((route, index) => {
console.log(`${index + 1}. ${route.strategy}: ${route.distance.toFixed(2)}km, 预计${route.estimatedTime.toFixed(0)}分钟`);
});
console.log('\n=== 导航统计 ===');
const stats = navigation.getNavigationStats();
console.log('统计信息:', JSON.stringify(stats, null, 2));
} catch (error) {
console.error('路径规划示例出错:', error.message);
}
}
// 运行示例
navigationExample();策略模式的关键要点
1. 策略接口设计
javascript
// 策略接口应该简单明确
class Strategy {
// 通常只包含一个主要方法
execute(data) {
// 核心算法逻辑
}
// 可以包含辅助方法
validate(data) {
// 验证输入数据
}
}2. 上下文设计
javascript
class Context {
constructor(strategy) {
this.strategy = strategy;
}
// 设置新策略
setStrategy(strategy) {
this.strategy = strategy;
}
// 执行策略
execute(data) {
return this.strategy.execute(data);
}
}3. 策略选择
javascript
class StrategySelector {
// 根据条件选择策略
selectStrategy(condition) {
if (condition === 'fast') {
return new FastStrategy();
} else if (condition === 'cheap') {
return new CheapStrategy();
} else {
return new DefaultStrategy();
}
}
}策略模式与其它模式的对比
策略模式 vs 状态模式
javascript
// 策略模式 - 算法选择
class StrategyContext {
setStrategy(strategy) {
this.strategy = strategy;
}
execute() {
return this.strategy.execute();
}
}
// 状态模式 - 对象状态变化
class StateContext {
setState(state) {
this.state = state;
}
request() {
this.state.handle(this);
}
}策略模式 vs 命令模式
javascript
// 策略模式 - 算法封装
class Strategy {
execute(data) {
// 执行算法
}
}
// 命令模式 - 请求封装
class Command {
execute() {
// 执行请求
}
undo() {
// 撤销请求
}
}策略模式的优缺点
优点
- 算法可替换:可以在运行时切换算法
- 避免条件语句:减少 if-else 或 switch-case 语句
- 符合开闭原则:增加新算法无需修改现有代码
- 算法复用:不同上下文可以复用相同算法
- 测试友好:每个算法可以独立测试
缺点
- 对象数量增加:每种算法都需要一个策略类
- 客户端了解策略:客户端需要知道所有策略的区别
- 通信开销:策略对象可能传递大量数据
- 复杂性增加:简单的算法可能不需要策略模式
总结
策略模式是一种行为设计模式,它能让你定义一系列算法,并将每种算法分别放入独立的类中,使算法的变化独立于使用它们的客户端。策略模式让算法的变化独立于使用算法的客户。
通过本章的学习,我们了解了:
- 策略模式的基本概念和核心思想
- 策略模式的实现方式和关键要点
- 策略模式在实际开发中的应用场景(排序算法、支付方式、路径规划)
- 策略模式与其他行为型模式的对比
- 策略模式的优缺点
策略模式在现代软件开发中应用广泛,特别是在需要实现算法多样性、支持运行时算法切换、避免大量条件判断语句的场景中,它可以很好地支持系统的灵活性和可维护性。
在下一章中,我们将继续探讨其他行为型模式,接下来是模板方法模式。