一、概述
策略模式(Strategy Pattern)定义了一组同类型的算法,在不同的类中封装起来,每种算法可以根据当前场景相互替换,从而使算法的变化独立于使用它们的客户端(即算法的调用者),这种类型的设计模式属于行为型模式。
通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。
二、模块
- 环境(Context):维护一个对策略对象的引用,负责将客户端请求委派给具体的策略对象执行。环境类可以通过依赖注入、简单工厂等方式来获取具体策略对象。
- 抽象策略(Abstract Strategy):定义了策略对象的公共接口或抽象类,规定了具体策略类必须实现的方法。
- 具体策略(Concrete Strategy):实现了抽象策略定义的接口或抽象类,包含了具体的算法实现。
三、示例
假如要处理一个不同类型文件后缀的方法,需要大量的if-else 操作,后续的扩展和维护会变得非常复杂且容易出错。
if(){
}else if(){
}else if(){
}
........
}
在阿里《Java开发手册》中,有这样的规则:超过3层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。
四、代码
第一步:创建抽象策略
/*
*
* 抽象策略
*/
public interface DocumentHandlerStrategy {
void doSomething();
}
第二步:创建具体策略
/**
* 具体策略处理deb文件
*/
public class HandlerDebStrategy implements DocumentHandlerStrategy {
@Override
public void doSomething() {
System.out.println("处理DEB文件");
}
}
/**
* 具体策略处理exe文件
*/
public class HandlerExeStrategy implements DocumentHandlerStrategy {
@Override
public void doSomething() {
System.out.println("处理EXE文件");
}
}
/**
* 具体策略处理txt文件
*/
public class HandlerTxtStrategy implements DocumentHandlerStrategy {
@Override
public void doSomething() {
System.out.println("处理TXT文件");
}
}
第三步:创建环境Context
/**
* 环境Context
*/
public class DocumentStrategyContext {
private static final Map<String, DocumentHandlerStrategy> strategyMap = new HashMap<>();
static {
strategyMap.put("txt", new HandlerTxtStrategy());
strategyMap.put("exe", new HandlerExeStrategy());
strategyMap.put("deb", new HandlerDebStrategy());
}
public static DocumentHandlerStrategy getHandlerStrategy(String type) {
return strategyMap.get(type);
}
}
五、测试
/**
* @author wk
* @creat 2023-07-30-21:55
*/
public class StrategyReplaceIfElseDemo {
public static void main(String[] args) {
DocumentHandlerStrategy strategy = DocumentStrategyContext .getHandlerStrategy("deb");
strategy.doSomething();
}
}
测试结果:
处理DEB文件
六、思考与总结
优点:
- 可以动态切换具体策略类,不需要修改上下文类的代码,提高了代码的灵活性和可维护性。
- 可以避免使用复杂的条件语句或者多层嵌套等,提高了代码的可读性和易用性。
- 可以使算法、业务规则等更加独立和可测试,从而降低了耦合性和复杂度。
缺点:
- 需要定义和管理大量的具体策略类,增加了代码量和维护难度。
- 如果策略接口较为复杂或者需要频繁调整,可能会导致系统性能下降。
使用场景:
- 策略模式是解决过多 if-else(或者 switch-case) 代码块的方法之一,提高代码的可维护性、可扩展性和可读性。