设计模式-策略模式(Strategy)
- 一、策略模式概述
- 1.1 什么是策略模式
- 1.2 简单实现策略模式
- 1.3 使用策略模式的注意事项
- 二、策略模式的用途
- 三、策略模式实现方式
- 3.1 简单策略模式
- 3.2 组合策略模式
- 3.3 动态策略模式
一、策略模式概述
1.1 什么是策略模式
策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换或独立于使用它的客户而变化。这种类型的设计模式属于行为型模式。当在处理一项业务时,如果有多种处理方式,并且需要再运行时决定使用哪一种具体实现,就会使用策略模式。
策略模式的主要组成部分包括抽象策略(Strategy)类、具体策略(Concrete Strategy)类和环境(Context)类。抽象策略类是策略接口,定义了所有支持的算法;具体策略类是实现了抽象策略接口的类,表示每种具体的算法;环境类则负责接受客户的请求,并确定使用哪种具体策略来处理该请求。
策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性。缺点在于增加了系统的复杂性和理解难度。
1.2 简单实现策略模式
首先,定义一个策略接口:
public interface Strategy {void execute();
}
然后,创建具体策略类实现该接口:
public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略B");}
}
接下来,创建一个上下文类,用于管理策略:
public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}
最后,在主函数中测试策略模式:
public class Main {public static void main(String[] args) {Context context = new Context(new ConcreteStrategyA()); // 使用策略A初始化上下文对象context.executeStrategy(); // 输出:执行策略Acontext.setStrategy(new ConcreteStrategyB()); // 更改上下文对象的策略为策略Bcontext.executeStrategy(); // 输出:执行策略B}
}
在这个示例中,我们定义了一个策略接口Strategy,并创建了两个具体策略类ConcreteStrategyA和ConcreteStrategyB。Context类负责管理当前策略,并在需要时更改策略。通过调用context.executeStrategy()方法,我们可以执行当前策略
1.3 使用策略模式的注意事项
- 1、当一个系统的策略多于四个时,需要考虑使用混合模式,解决策略类膨胀的问题。
- 2、策略模式包含四个核心角色:环境(Context)、抽象策略(Abstract Strategy)、具体策略(Concrete Strategy)和客户端。客户端代码不需要知道具体的算法细节,而是通过调用环境类来使用所选择的策略。
- 3、策略模式的优点在于降低系统的耦合度,提高系统的灵活性和扩展性,但增加了系统的复杂性和理解难度。如果使用得当,可以避免使用多重条件语句,如if…else语句、switch…case语句。
- 4、由于所有策略类都需要对外暴露,可能会增加系统的复杂度和维护难度。在设计时需要充分考虑这一点。
二、策略模式的用途
策略模式是一种行为型设计模式,它主要用于解决算法选择问题。其主要特点在于能够将一系列算法封装起来,并让它们可以互相替换或独立于使用它的客户而变化。
策略模式的应用场景主要包括以下两种:
- 1、行为切换:当系统的许多类的区别仅在于其行为不同时,可以使用策略模式将这些不同的行为动态地让用户对象在其间进行选择。例如,对于同一个计算问题,用户可以选择使用加法策略将两个数相加,也可以选择使用乘法策略将两个数相乘。在这种情况下,每种策略都封装了一套独立的业务逻辑和计算方式。
- 2、算法选择:在需要动态地在几种算法中选择一种的场景下,也可以使用策略模式。比如在处理大量数据时,我们可能需要根据具体情况选择最合适的排序算法,如冒泡排序、快速排序或归并排序等。这时,每种排序算法都可以被视为一种策略。
策略模式的优点主要在于降低了系统的耦合度,提高了系统的灵活性和扩展性。通过使用策略模式,我们可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。此外,策略模式提供了对开闭原则的支持,即在不修改原有系统的基础上选择不同的行为,也可以额外扩展其它行为。
三、策略模式实现方式
3.1 简单策略模式
首先,我们定义一个策略接口:
public interface Strategy {void execute();
}
然后,我们创建两个具体的策略类,分别实现这个接口:
public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略 A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略 B");}
}
接下来,我们创建一个上下文类,用于根据需要选择不同的策略:
public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}
最后,我们在客户端代码中使用这些类:
public class Client {public static void main(String[] args) {// 使用策略 AContext context = new Context(new ConcreteStrategyA());context.executeStrategy();// 切换到策略 Bcontext.setStrategy(new ConcreteStrategyB());context.executeStrategy();}
}
运行客户端代码,将输出:
执行策略 A
执行策略 B
3.2 组合策略模式
首先,创建一个抽象组件接口(IStrategy):
public interface IStrategy {void execute();
}
然后,创建具体组件类(ConcreteComponent),它实现了抽象组件接口:
public class ConcreteComponent implements IStrategy {@Overridepublic void execute() {System.out.println("执行具体组件的操作");}
}
接下来,创建上下文类(Context),它也实现了抽象组件接口。在上下文类中,我们可以添加一个成员变量来存储具体的策略对象,并提供一个方法来设置具体的策略对象:
public class Context implements IStrategy {private IStrategy strategy;public void setStrategy(IStrategy strategy) {this.strategy = strategy;}@Overridepublic void execute() {if (strategy != null) {strategy.execute();} else {System.out.println("没有设置策略");}}
}
最后,创建具体的策略类(ConcreteStrategyA 和 ConcreteStrategyB),它们也实现了抽象组件接口:
public class ConcreteStrategyA implements IStrategy {@Overridepublic void execute() {System.out.println("执行策略A的操作");}
}public class ConcreteStrategyB implements IStrategy {@Overridepublic void execute() {System.out.println("执行策略B的操作");}
}
在客户端代码中,我们可以创建一个上下文对象,然后根据需要设置不同的策略对象,并执行相应的操作:
public class Client {public static void main(String[] args) {Context context = new Context();context.setStrategy(new ConcreteStrategyA());context.execute(); // 输出:执行策略A的操作context.setStrategy(new ConcreteStrategyB());context.execute(); // 输出:执行策略B的操作}
}
这个示例展示了如何在运行时动态地改变对象的行为。通过使用组合策略模式,我们可以轻松地为对象添加新的策略,而无需修改其现有代码。
3.3 动态策略模式
首先,创建一个策略接口:
public interface Strategy {void execute();
}
然后,创建两个实现策略接口的具体策略类:
public class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("执行策略A");}
}public class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("执行策略B");}
}
接下来,创建一个上下文类,用于根据条件选择并执行相应的策略:
public class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
}
最后,在客户端代码中,可以根据条件创建不同的策略对象,并将其设置到上下文对象中,然后执行策略:
public class Client {public static void main(String[] args) {// 根据条件选择策略AStrategy strategyA = new ConcreteStrategyA();Context context = new Context(strategyA);context.executeStrategy(); // 输出:执行策略A// 根据条件选择策略BStrategy strategyB = new ConcreteStrategyB();context.setStrategy(strategyB);context.executeStrategy(); // 输出:执行策略B}
}
通过这种方式,可以在运行时根据条件动态地改变策略对象,从而实现动态策略模式。