策略模式的要点
策略模式(Strategy Pattern)是一种行为设计模式,主要用于定义一系列算法,并将每一个算法封装起来,使它们可以相互替换。其主要要点包括:
- 定义算法族:将算法定义为一系列可互换的策略类。
- 封装变化:将算法的具体实现封装在策略类中,使得算法的变化不会影响使用算法的客户端。
- 独立实现:每个策略类可以独立实现不同的算法,不影响其他策略。
- 运行时切换:客户端可以在运行时选择或切换不同的策略,而无需修改客户端代码。
- 遵循开闭原则:新增策略类时,无需修改现有代码,符合开闭原则(对扩展开放,对修改关闭)。
策略模式的组成部分
- 策略接口(Strategy):定义算法的公共接口。
- 具体策略类(ConcreteStrategy):实现策略接口的具体算法。
- 上下文类(Context):持有一个策略接口的引用,使用策略对象来完成算法。
具体例子
以下是一个简单的策略模式示例,展示不同的排序算法:
策略接口:
public interface SortStrategy {
void sort(int[] array);
}
具体策略类:
public class BubbleSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Bubble Sort");
// 冒泡排序算法实现
}
}
public class QuickSortStrategy implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Quick Sort");
// 快速排序算法实现
}
}
上下文类:
public class SortingContext {
private SortStrategy strategy;
public void setStrategy(SortStrategy strategy) {
this.strategy = strategy;
}
public void sortArray(int[] array) {
strategy.sort(array);
}
}
客户端代码:
public class StrategyPatternExample {
public static void main(String[] args) {
int[] array = {5, 2, 9, 1, 5, 6};
SortingContext context = new SortingContext();
// 使用冒泡排序策略
context.setStrategy(new BubbleSortStrategy());
context.sortArray(array);
// 使用快速排序策略
context.setStrategy(new QuickSortStrategy());
context.sortArray(array);
}
}
在Spring中的实现
在Spring中,可以通过注解和依赖注入实现策略模式。以下是一个示例:
策略接口和具体策略类:
public interface PaymentStrategy {
void pay(int amount);
}
@Component
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
@Component
public class PayPalPayment implements PaymentStrategy {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using PayPal.");
}
}
上下文类:
@Component
public class PaymentContext {
private final Map<String, PaymentStrategy> strategies;
@Autowired
public PaymentContext(List<PaymentStrategy> strategyList) {
strategies = strategyList.stream().collect(Collectors.toMap(
s -> s.getClass().getSimpleName(), s -> s
));
}
public void pay(String strategyName, int amount) {
PaymentStrategy strategy = strategies.get(strategyName);
if (strategy != null) {
strategy.pay(amount);
} else {
throw new IllegalArgumentException("No such payment strategy: " + strategyName);
}
}
}
客户端代码:
@SpringBootApplication
public class StrategyPatternSpringExample implements CommandLineRunner {
@Autowired
private PaymentContext paymentContext;
public static void main(String[] args) {
SpringApplication.run(StrategyPatternSpringExample.class, args);
}
@Override
public void run(String... args) throws Exception {
paymentContext.pay("CreditCardPayment", 100);
paymentContext.pay("PayPalPayment", 200);
}
}
在Java类库中的示例
-
java.util.Comparator
:Comparator
接口本质上就是策略模式的一个应用。不同的Comparator
实现可以定义不同的比较策略。- 示例:
List<String> list = Arrays.asList("banana", "apple", "cherry"); Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } });
-
javax.swing
:- 在Swing中,
LayoutManager
接口及其实现类也应用了策略模式,不同的布局管理器实现了不同的布局策略。 - 示例:
JFrame frame = new JFrame(); frame.setLayout(new BorderLayout());
- 在Swing中,
在Angular中的示例
在Angular中,策略模式可以用来处理不同的策略,比如数据格式化、验证等。以下是一个示例:
策略接口和具体策略类:
// 策略接口
export interface FormatterStrategy {
format(data: any): string;
}
// 具体策略类
export class JsonFormatter implements FormatterStrategy {
format(data: any): string {
return JSON.stringify(data, null, 2);
}
}
export class XmlFormatter implements FormatterStrategy {
format(data: any): string {
// 简单的XML格式化示例
return `<data>${data}</data>`;
}
}
上下文类:
import { Injectable } from '@angular/core';
import { FormatterStrategy } from './formatter-strategy';
@Injectable({
providedIn: 'root',
})
export class FormatterContext {
private strategy: FormatterStrategy;
setStrategy(strategy: FormatterStrategy) {
this.strategy = strategy;
}
formatData(data: any): string {
return this.strategy.format(data);
}
}
组件使用示例:
import { Component, OnInit } from '@angular/core';
import { FormatterContext } from './formatter-context';
import { JsonFormatter } from './json-formatter';
import { XmlFormatter } from './xml-formatter';
@Component({
selector: 'app-root',
template: `
<div>
<button (click)="useJson()">Use JSON Formatter</button>
<button (click)="useXml()">Use XML Formatter</button>
<pre>{{ formattedData }}</pre>
</div>
`,
})
export class AppComponent implements OnInit {
formattedData: string;
constructor(private formatterContext: FormatterContext) {}
ngOnInit() {
this.useJson();
}
useJson() {
this.formatterContext.setStrategy(new JsonFormatter());
this.formattedData = this.formatterContext.formatData({ name: 'Angular', version: '12' });
}
useXml() {
this.formatterContext.setStrategy(new XmlFormatter());
this.formattedData = this.formatterContext.formatData('Angular 12');
}
}
在React中的示例
在React中,策略模式可以用来处理不同的策略,比如数据格式化、验证等。以下是一个示例:
策略接口和具体策略类:
// 策略接口
class FormatterStrategy {
format(data) {
throw new Error("This method should be overridden.");
}
}
// 具体策略类
class JsonFormatter extends FormatterStrategy {
format(data) {
return JSON.stringify(data, null, 2);
}
}
class XmlFormatter extends FormatterStrategy {
format(data) {
// 简单的XML格式化示例
return `<data>${data}</data>`;
}
}
上下文类:
class FormatterContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
formatData(data) {
return this.strategy.format(data);
}
}
组件使用示例:
import React, { useState } from "react";
const formatterContext = new FormatterContext(new JsonFormatter());
function App() {
const [formattedData, setFormattedData] = useState("");
const useJson = () => {
formatterContext.setStrategy(new JsonFormatter());
setFormattedData(formatterContext.formatData({ name: "React", version: "17" }));
};
const useXml = () => {
formatterContext.setStrategy(new XmlFormatter());
setFormattedData(formatterContext.formatData("React 17"));
};
return (
<div>
<button onClick={useJson}>Use JSON Formatter</button>
<button onClick={useXml}>Use XML Formatter</button>
<pre>{formattedData}</pre>
</div>
);
}
export default App;