【设计模式】【行为型模式(Behavioral Patterns)】之策略模式(Strategy Pattern)
1. 设计模式原理说明
策略模式(Strategy Pattern) 是一种行为设计模式,它允许你定义一系列算法,并将每个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户。通过这种方式,客户端可以根据不同的情况选择不同的算法,而不需要修改其内部结构。
主要角色
- Context(上下文):使用某个策略类的对象。它维护着对Strategy对象的引用,用于在运行时切换策略。
- Strategy(策略接口):定义所有支持的算法的公共接口。Context使用这个接口来调用具体的策略。
- ConcreteStrategy(具体策略):实现了Strategy接口的具体算法。
2. UML 类图及解释
UML 类图
+------------------+ +-----------------------+
| Context | | Strategy Interface |
|------------------| |-----------------------|
| - strategy: Strategy | | - execute(context): void |
|------------------| +-----------------------+
| - setStrategy(strategy: Strategy) | ^
| - performOperation() | |
+------------------+ +-----------------------+
|
|
v
+---------------------------+
| ConcreteStrategyA |
|--------------------------|
| - execute(context): void |
+---------------------------+
^
|
+---------------------------+
| ConcreteStrategyB |
|--------------------------|
| - execute(context): void |
+---------------------------+
类图解释
- Context:维护对Strategy对象的引用,并提供一个方法
performOperation()
来执行策略。客户端通过这个方法来调用具体的策略。 - Strategy:定义了所有支持的算法的公共接口。Context使用这个接口来调用具体的策略。
- ConcreteStrategyA 和 ConcreteStrategyB:实现了Strategy接口的具体算法。客户端可以选择不同的具体策略来执行不同的算法。
3. 代码案例及逻辑详解
Java 代码案例
// 策略接口
interface Strategy {
void execute();
}
// 具体策略A
class ConcreteStrategyA implements Strategy {
@Override
public void execute() {
System.out.println("Executing strategy A");
}
}
// 具体策略B
class ConcreteStrategyB implements Strategy {
@Override
public void execute() {
System.out.println("Executing strategy B");
}
}
// 上下文
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void performOperation() {
strategy.execute();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategyA());
context.performOperation(); // 输出: Executing strategy A
context.setStrategy(new ConcreteStrategyB());
context.performOperation(); // 输出: Executing strategy B
}
}
C++ 代码案例
#include <iostream>
// 策略接口
class Strategy {
public:
virtual void execute() = 0;
virtual ~Strategy() {}
};
// 具体策略A
class ConcreteStrategyA : public Strategy {
public:
void execute() override {
std::cout << "Executing strategy A" << std::endl;
}
};
// 具体策略B
class ConcreteStrategyB : public Strategy {
public:
void execute() override {
std::cout << "Executing strategy B" << std::endl;
}
};
// 上下文
class Context {
private:
Strategy* strategy;
public:
Context(Strategy* strategy) : strategy(strategy) {}
void setStrategy(Strategy* strategy) {
this->strategy = strategy;
}
void performOperation() {
strategy->execute();
}
~Context() {
delete strategy;
}
};
// 客户端
int main() {
Context context(new ConcreteStrategyA());
context.performOperation(); // 输出: Executing strategy A
context.setStrategy(new ConcreteStrategyB());
context.performOperation(); // 输出: Executing strategy B
return 0;
}
Python 代码案例
# 策略接口
class Strategy:
def execute(self):
raise NotImplementedError
# 具体策略A
class ConcreteStrategyA(Strategy):
def execute(self):
print("Executing strategy A")
# 具体策略B
class ConcreteStrategyB(Strategy):
def execute(self):
print("Executing strategy B")
# 上下文
class Context:
def __init__(self, strategy: Strategy):
self._strategy = strategy
def set_strategy(self, strategy: Strategy):
self._strategy = strategy
def perform_operation(self):
self._strategy.execute()
# 客户端
if __name__ == "__main__":
context = Context(ConcreteStrategyA())
context.perform_operation() # 输出: Executing strategy A
context.set_strategy(ConcreteStrategyB())
context.perform_operation() # 输出: Executing strategy B
Go 代码案例
package main
import (
"fmt"
)
// 策略接口
type Strategy interface {
execute()
}
// 具体策略A
type ConcreteStrategyA struct{}
func (c *ConcreteStrategyA) execute() {
fmt.Println("Executing strategy A")
}
// 具体策略B
type ConcreteStrategyB struct{}
func (c *ConcreteStrategyB) execute() {
fmt.Println("Executing strategy B")
}
// 上下文
type Context struct {
strategy Strategy
}
func NewContext(strategy Strategy) *Context {
return &Context{strategy: strategy}
}
func (c *Context) SetStrategy(strategy Strategy) {
c.strategy = strategy
}
func (c *Context) PerformOperation() {
c.strategy.execute()
}
// 客户端
func main() {
context := NewContext(&ConcreteStrategyA{})
context.PerformOperation() // 输出: Executing strategy A
context.SetStrategy(&ConcreteStrategyB{})
context.PerformOperation() // 输出: Executing strategy B
}
4. 总结
策略模式 是一种行为设计模式,它允许你定义一系列算法,并将每个算法封装起来,使它们可以互换。这种模式的主要目的是在不改变客户端代码的情况下,通过不同的策略来实现不同的行为。
主要优点
- 算法可互换:可以在运行时动态地选择不同的算法,提高了灵活性。
- 职责分离:将算法的实现和使用算法的客户端分离,降低了耦合度。
- 易于扩展:增加新的策略非常容易,只需要实现策略接口即可。
主要缺点
- 增加了类的数量:每种策略都需要一个具体的类,可能会导致类的数量增多。
- 客户端需要了解所有策略:客户端需要知道所有的策略类,以便在运行时选择合适的策略。
适用场景
- 当有多个相似的算法需要根据环境或条件动态选择时。
- 当需要在运行时动态地改变对象的行为时。
- 当类的行为由其子类决定时,可以考虑使用策略模式来避免大量的子类继承。
- 当需要封装不同的算法或行为,并且这些算法或行为可以互换时。