在项目中应用“观察者模式”清除层层if...else if...
的臃肿代码
文章目录
一、前言
最近在项目用到了二十三种设计模式中的“观察者模式”,改善了代码结构,消除了层层if...else if...else if...
的臃肿代码。深刻体会了这种“高明”的经验所带来的好处,感觉很开心,在此记录一下。
二、项目中遇到的问题
在项目开发中遇到这样一个场景:
客户将多个业务场景下的数据以excel文件的形式整理出来,每种业务场景下整理出的excel内容排版格式都不一样。现在需要开发程序将这些excel解析出来,存到关系库中,后续对这些数据进行其他的处理。
因为每种业务场景下的excel文件内容排版都不一样,所以要根据业务场景写特定的解析程序。最初的设计如下:
public void parseExcelFileBySceneType(String scenetype,File excelFile){
if (StringUtils.equals(scenetype,"static_type")){
parseStaticTypeExcel(excelFile);
}else if(StringUtils.equals(scenetype,"supper_type")){
parseSupperTypeExcel(excelFile);
}else if(StringUtils.equals(scenetype,"run_type")){
parseRunTypeExcel(excelFile);
}else if(StringUtils.equals(scenetype,"bench_type")){
parseBenchTypeExcel(excelFile);
}else{
throw new RuntimeException("该功能不存在");
}
}
可以看上,每多一个业务场景,上面的代码就要多一层else...if
,因此代码变得越来越臃肿。
三、用观察者模式解决
现在使用“观察者模式”设计出更优化的解决方案。
3.1 观察者模式回顾
在观察者模式中,主要有两类角色:主题(subject)、观察者(observer)。
3.2 项目中使用观察者模式的思路
-
主题
带解析的excel文件,根据业务场景的不同,需要让特定的观察者去解析处理。
-
观察者
一个观察者只解析特定业务场景下的excel文件。
3.3 代码示例
-
观察者接口:
public interface ParseFileObserver{ String getSceneType(); /** * 解析文件 */ void parseFile(File excelFile); }
-
主题接口:
public interface ParseFileSubject{ /** * 注册观察者 */ void registerObserver(ParseFileObserver observer); /** * 通知特定的观察者对excel解析 */ void notifyObserver(String sceneType,excelFile); }
-
主题接口的实现类
public class ParseFileSubjectImpl implement ParseFileSubject{ /** 存放业务场景与观察者的一一映射 */ private Map<String,ParseFileObserver> observerMap = new HashMap<>(); /** 将业务场景和对应的观察者存放到映射表中 */ @Override public void registerObserver(ParseFileObserver observer){ observerMap.put(observer.getSceneType(),observer); } /** 让特定的观察者处理excel的解析 */ @Override public void notifyObserver(String sceneType,excelFile){ if(StringUtils.isBlank(sceneType)){ throw new IllegalArgumentException("sceneType cannot empty"); }else if(observerMap.containsKey(sceneType)){ observerMap.get(sceneType).parseFile(excelFile); }else{ throw new RuntimeException(String.format("%s业务场景下的解析功能还未开发",sceneType)) } } }
-
观察者接口的实现类(多个):
第一个观察者
StaticTypeObserver
:public class StaticTypeObserver implement ParseFileObserver{ private String sceneType; public StaticTypeObserver(ParseFileSubject parseFileSubject){ // 可以定义一个枚举来赋值 sceneType="staticType"; parseFileSubject.registerObserver(this); } @Override public String getSceneType(){ return this.sceneType; } /** 解析excel业务的流畅 */ @Override public void parseFile(File excelFile){ // 解析该场景下excel文件的逻辑 } }
第二个观察者
SupperTypeObserver
:public class SupperTypeObserver implement ParseFileObserver{ private String sceneType; public SupperTypeObserver(ParseFileSubject parseFileSubject){ // 可以定义一个枚举来赋值 sceneType="supperType"; parseFileSubject.registerObserver(this); } @Override public String getSceneType(){ return this.sceneType; } /** 解析excel业务的流畅 */ @Override public void parseFile(File excelFile){ // 解析该场景下excel文件的逻辑 } }
其他观察者:
……