设计模式笔记_行为型_策略模式
1. 策略模式介绍
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换。这种模式使得算法可以在不影响客户端的情况下发生变化。
类比场景:可以将策略模式类比为选择出行方式的场景。假设你要从一个城市到另一个城市,你可以选择不同的出行方式,比如开车、坐火车、或者乘飞机。每种方式都有自己的优缺点,但最终目的是到达目的地。策略模式就像是为你提供了一种机制来选择最适合当前情况的出行方式。
结构:策略模式通常由以下几个部分组成:
- 策略接口(Strategy Interface):定义了一个通用接口,所有具体策略类都实现这个接口。
- 具体策略类(Concrete Strategy Class):实现策略接口,提供具体的算法。
- 上下文类(Context Class):持有一个策略接口的引用,负责动态地选择和执行某个具体策略。上下文类在策略模式中扮演着一个重要角色,它不仅负责持有策略对象,还可能包含一些与策略相关的状态信息或辅助方法,以便于策略的执行。
优点:
- 灵活性:可以根据需要在运行时动态地改变对象的算法或行为。
- 扩展性:增加新的策略时,只需添加新的策略类即可,无需修改已有代码。
- 简化代码:将算法的实现和使用分离,使代码更加简洁和易于维护。
2. 代码演示
场景:模拟出行方式,有开车、坐火车、或者乘飞机三种出行策略。
2.1 常规用法
策略接口(Strategy Interface):
public interface TravelStrategy {void travel();
}
具体策略类(Concrete Strategy Class):
// 具体策略类 - 开车
public class CarTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by car.");}
}// 具体策略类 - 火车
public class TrainTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by train.");}
}// 具体策略类 - 飞机
public class PlaneTravelStrategy implements TravelStrategy {@Overridepublic void travel() {System.out.println("Traveling by plane.");}
}
上下文类(Context Class):
public class TravelContext {private TravelStrategy strategy;//一些与策略相关的信息private String travelTime;public TravelContext(String travelTime) {this.travelTime = travelTime;}public void setStrategy(TravelStrategy strategy) {this.strategy = strategy;}public void executeTravel() {System.out.println("Travel time: " + travelTime);strategy.travel();}
}
客户端代码:使用策略模式
public class StrategyPatternDemo {public static void main(String[] args) {TravelContext context = new TravelContext("Morning");// 使用开车策略context.setStrategy(new CarTravelStrategy());context.executeTravel();// 使用火车策略context.setStrategy(new TrainTravelStrategy());context.executeTravel();// 使用飞机策略context.setStrategy(new PlaneTravelStrategy());context.executeTravel();}
}
对应的类图:
2.2 使用策略工厂优化
上述常规用法中,策略对象的创建比较简单,客户端在使用策略时顺手创建了对象。如果策略创建逻辑比较复杂,这种用法会增加客户端的复杂度,此时可以使用策略工厂优化。
策略工厂并不是策略模式的必需部分,但它可以在某些场景下增加策略模式的灵活性和可维护性。策略工厂的主要作用是负责创建策略对象,这样可以将策略的选择逻辑封装起来,使得客户端代码更简洁,并且可以更容易地管理和扩展策略。
引入策略工厂后,只需修改上下文类和客户端代码,其他保持不变。
新增策略工厂(StrategyFactory):
public class TravelStrategyFactory {public static TravelStrategy getStrategy(String preference) {switch (preference.toLowerCase()) {case "car":return new CarTravelStrategy();case "train":return new TrainTravelStrategy();case "plane":return new PlaneTravelStrategy();default:throw new IllegalArgumentException("Unknown travel preference: " + preference);}}
}
上下文类(Context Class)修改如下:
public class TravelContext {private TravelStrategy strategy;private String travelTime;public TravelContext(String travelTime) {this.travelTime = travelTime;}//根据用户选择的交通工具名称,使用策略工厂获取对应策略public void setStrategy(String preference) {this.strategy = TravelStrategyFactory.getStrategy(preference);}public void executeTravel() {System.out.println("Travel time: " + travelTime);strategy.travel();}
}
客户端代码修改如下:
public class StrategyPatternDemo {public static void main(String[] args) {TravelContext context = new TravelContext("Morning");// 使用开车策略; 直接传入交通工具名称即可context.setStrategy("car");context.executeTravel();// 使用火车策略context.setStrategy("train");context.executeTravel();// 使用飞机策略context.setStrategy("plane");context.executeTravel();}
}
对应的类图:
引入策略工厂的优点:
- 封装选择逻辑:策略工厂将策略选择的逻辑集中在一个地方,使得上下文或客户端代码更简洁。
- 易于扩展:当需要添加新的策略时,只需更新工厂的创建逻辑,而不需要修改上下文或客户端代码。
- 减少耦合:上下文或客户端代码与具体策略的创建解耦,使得代码更易于维护。
虽然策略工厂不是策略模式的核心部分,但在一些复杂的场景中,它可以显著提高代码的组织性和可维护性。根据项目需求和复杂度,可以选择是否使用策略工厂。