- 什么是策略模式
- 策略模式是用来干什么的
- 代码实现
- 什么场景适合使用
- 优缺点
一、策略模式
策略模式是一种面向对象设计模式,它允许在运行时选择算法的行为。这种模式使得可以定义一系列算法,并将每种算法封装起来,使它们可以相互替换,而不会影响到使用这些算法的客户端。
策略模式的主要角色如下。
- 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
我自己的理解:策略模式是在我们对一件事情实现的方法(策略),比如说要去西安旅行,去的方式有飞机、火车、大巴、自驾等。这些出行方式就是一个个不同的策略,可以根据自己的需求选择合适的策略。去的行为我们可以抽象成一个策略,然后去的方式是具体的策略,环境就是提供给我们选择的。
二、策略模式的作用
-
分离算法: 策略模式通过将算法的实现从上下文中分离,使得算法可以独立于客户端而变化。这样,可以更轻松地添加、删除或替换算法,而不影响上下文的代码。
-
灵活性: 它允许在运行时动态地选择算法。这对于需要根据不同条件或用户输入选择不同行为的系统来说是非常有用的。
-
可维护性: 策略模式使得每个算法都被封装在自己的类中,这样有助于代码的理解、扩展和维护。算法的变化不会影响到其他部分的代码。
-
重用性: 不同的上下文可以共享相同的策略,从而提高了代码的重用性。一个策略可以在多个地方使用而无需修改。
-
避免条件语句的过度复杂性: 在没有策略模式的情况下,可能需要使用大量的条件语句来根据不同情况执行不同的行为。策略模式可以帮助减少这种复杂性,使代码更加清晰和可维护。
三、代码实现
1、创建抽象策略 ,为具体策略定义好一个公共接口;
/**
* @author qiu
* @date 2024/1/10--11:10
* 抽象策略 出行
**/
public interface TravelDemo {
/**
* 出行
*/
void travel();
}
2、创建具体的策略,其通过接口来实现抽象策略类,同时封装了具体的算法
/**
* @author qiu
* @date 2024/1/10--11:13
**/
public class AircraftTravel implements TravelDemo{
@Override
public void travel() {
System.out.println("坐飞机咯");
}
}
/**
* @author qiu
* @date 2024/1/10--11:14
**/
public class TrainTravel implements TravelDemo{
@Override
public void travel() {
System.out.println("坐火车出行");
}
}
/**
* @author qiu
* @date 2024/1/10--11:15
**/
public class BusTravel implements TravelDemo{
@Override
public void travel() {
System.out.println("做大巴车出行");
}
}
3、创建环境类,持有一个抽象策略类的引用,提供给客户端调用
/**
* @author qiu
* @date 2024/1/10--11:15
* 环境类 持有一个抽象策略类的引用,提供给客户端调用
**/
public class TravelContext {
private TravelDemo travelDemo;
public TravelContext(TravelDemo travelDemo) {
this.travelDemo = travelDemo;
}
public void selectTravel(String name){
System.out.println(name+"选择的出行方式是:");
travelDemo.travel();
}
}
4、测试
/**
* @author qiu
* @date 2024/1/10--11:18
* 测试
**/
public class TravelTest {
public static void main(String[] args) {
TravelContext travelContext;
TravelDemo aircraftTravel = new AircraftTravel();
travelContext = new TravelContext(aircraftTravel);
travelContext.selectTravel("小明");
System.out.println();
TravelDemo trainTravel = new TrainTravel();
travelContext = new TravelContext(trainTravel);
travelContext.selectTravel("小王");
}
}
四、适用场景
-
多算法共存: 当一个系统中有多个算法,而且需要动态地在这些算法中选择一个时,策略模式就很有用。例如,排序算法、压缩算法、数据验证等。
-
避免使用条件语句: 当在代码中存在大量的条件语句,而且这些条件语句会根据不同的情况选择不同的行为时,可以考虑使用策略模式。这有助于避免条件语句的过度复杂性,提高代码的可读性和可维护性。
-
算法需要独立于客户端: 如果算法的实现可以独立于调用它的客户端,并且不希望客户端知道算法的具体实现细节,那么可以使用策略模式。
-
需要动态切换算法: 当需要在运行时动态选择算法时,策略模式提供了一种灵活的方式,可以在不修改客户端代码的情况下切换算法。
-
算法有不同变体: 如果一个算法有多个变体,而且这些变体需要在运行时进行切换,策略模式可以很好地应对这种情况。
-
系统中有复杂的条件分支: 当系统中存在复杂的条件分支,并且这些条件分支与算法的选择有关时,使用策略模式可以简化代码结构。
举例来说,一个电商平台可能需要根据不同的促销活动计算折扣,策略模式可以用来封装每种折扣算法,而客户端只需选择适当的折扣策略,而无需关心具体的计算细节。这样,当新的促销活动出现时,只需添加新的策略而不必修改已有的代码。
五、优缺点
优点:
-
灵活性和可扩展性: 策略模式使得算法可以独立于客户端变化,易于扩展和添加新的算法。新的算法可以很容易地加入系统,而不会影响原有的代码。
-
避免条件语句: 策略模式可以避免大量的条件语句,提高代码的可读性和可维护性。每个算法都被封装在自己的策略类中,使得代码结构更清晰。
-
可复用性: 策略模式提高了代码的可复用性。不同的上下文可以共享相同的策略,而无需修改策略的代码。
-
易于测试: 策略模式使得单元测试更容易进行。由于每个算法都被封装在自己的类中,可以单独测试每个策略的行为。
缺点:
-
类数量增加: 策略模式会增加类的数量,因为每个具体策略都需要一个独立的类。对于只有少数几种算法的情况,可能会显得过于繁琐。
-
客户端必须了解不同的策略: 客户端必须知道每个策略的存在,以便在运行时选择合适的策略。这可能会使客户端代码变得复杂,特别是在有许多策略时。
-
上下文必须了解策略的不同之处: 上下文必须了解每个策略的区别,以便在选择策略时能够判断哪一个最适合当前的情况。这可能导致上下文与策略的耦合。
总体来说,策略模式在需要动态选择算法、避免条件语句、提高可维护性和可扩展性的情况下非常有用,但在应用时需要权衡其优缺点。