介绍
经常写if和switch的朋友们可以考虑用策略模式替换原有写法。
策略模式允许我们定义一系列算法,将每一个算法封装起来,并使它们可以互相替换。
主要解决的问题:
- 当存在多种算法或策略可完成同一任务时,如何避免使用大量的条件语句(如if...else或switch...case)来决定使用哪种算法,从而提高代码的可读性和可维护性。
- 需要在运行时根据不同的条件选择不同的算法或策略。
基本结构:
- 策略接口(Strategy Interface):定义所有支持的算法的公共接口。策略接口使得算法可以互换。
- 具体策略类(Concrete Strategy Classes):实现了策略接口的类,每个类封装了一个具体的算法或策略。
- 上下文(Context):使用策略的类。上下文通常持有一个策略接口的引用,可以在运行时设置这个引用以切换到不同的策略。
实现案例
假设我们现在要处理一批文件,文件类型包括ppt、doc、xlsx等,需要根据传入文件类型不同调用不同的处理方法。
常规思路,if else或者switch,这两种都可以实现,但是有一个很明显的缺点,如果再增加一种文件类型,则需要改动判断逻辑,这不符合六大设计原则之开闭原则(一个软件实体应当对扩展开放,对修改关闭)
此时我们可以选择策略模式来替代if或switch模式,具体设计如下
策略接口
java
复制代码
public interface OfficeStrategy { /** * 文件处理策略 * * @param officeParam 入参 */ void handlerOffice(OfficeParam officeParam); }
策略实现类
java
复制代码
@Component public class DocOfficeStrategy implements OfficeStrategy { @Override public void handlerOffice(OfficeParam officeParam) { System.out.println("开始处理"+ officeParam.getFileType()); } } @Component public class PptOfficeStrategy implements OfficeStrategy{ @Override public void handlerOffice(OfficeParam officeParam) { System.out.println("开始处理"+ officeParam.getFileType()); } } @Component public class XlsxOfficeStrategy implements OfficeStrategy { @Override public void handlerOffice(OfficeParam officeParam) { System.out.println("开始处理"+ officeParam.getFileType()); } }
策略上下文
java
复制代码
@Component public class OfficeStrategyContext { @Autowired private final Map<String, OfficeStrategy> officeTypeStrategyMap = new ConcurrentHashMap<>(); public OfficeStrategy getStrategy(String flag) { return this.officeTypeStrategyMap.get(String.format("%sOfficeStrategy", flag)); } }
注意这里的细节,我们通过spring管理策略实现类,因此在OfficeStrategyContext中通过spring ioc机制注入所有策略类的实现,根据传入的策略类型,匹配相应的策略实现。
通过这种实现方式,如果需要处理新的业务类型,创建新的OfficeStrategy实现类,并且通过spring 管理bean,还会自动将新的实现类注入到officeTypeStrategyMap中,这样就避免if和switch方式中,新加一种业务类型就需要扩展条件判断的弊端,做到了对扩展开放,对修改关闭。
测试
我们在springboot项目中,使用junit测试策略类的加载和获取
java
复制代码
@ActiveProfiles("dev") @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest @Slf4j public class OfficeStrategyHandlerTest { @Autowired private OfficeStrategyContext officeStrategyContext; @Test public void testOfficeStrategy() { String fileType = "doc"; OfficeStrategy officeStrategy = officeStrategyContext.getStrategy(fileType); OfficeParam officeParam = new OfficeParam(); officeParam.setFileType(fileType); officeParam.setFilePath("test.doc"); officeStrategy.handlerOffice(officeParam); } }
优缺点
优点
算法的封装与复用:每个具体策略类封装了一个算法,易于理解和复用。 扩展性良好:新增策略不需要修改原有代码,符合开闭原则。 简化了单元测试:每个策略都可以独立测试,无需依赖其他策略。 提高了代码的灵活性和可读性:消除了条件语句,使得代码更加清晰。
缺点
- 类数量增多:每个具体策略都需要一个独立的类,如果策略较多,将导致类的数量增加。
应用场景
当有多个相似的行为,只在具体行为上有所不同,可以使用策略模式。 需要动态地在几种算法中切换的情况。 避免使用多重条件选择语句(如if...else或switch...case)来决定使用哪个算法或策略。