一、问题描述
if else if是代码中经常要用的语句块,如果选择分支不多的话还好,当时当选择分支很多的时候,就不能再这样做了;那么有什么办法可以优化多个选择分支结构呢?
需求如下所示:
/**
* 根据文件路径读取文件内容
* @param path FilePath
* @return ReadFileResultVO
*/
public ReadFileResultVO ReadFile(String path) {
if () {//如果是DOC类型的文件,则调用读取DOC文件的方法
}
else if () {//如果是DOCX类型的文件,则调用读取DOCX文件的方法
}
else if () {//如果是PDF类型的文件,则调用读取PDF文件的方法
}
else if () {//如果是OFD类型的文件,则调用读取OFD文件的方法
}
..........
}
二、解决办法
当选择结构过多时,就不再适用于if else方法了,此时我们可以使用设计模式中的策略模式+工厂模式优化if else语句块.
总体结构如下:
三、具体实现
- 总接口
ReadFileUtil.java
import com.xxx.utils.factory.api.IReadFileHandleStrategy;
import com.xxx.vo.ReadFileResultVO;
/**
* 工厂模式下的读取文件
* @author wxz
* @date 2023.4.12
* @version 1.0.0
*/
public class ReadFileUtil {
/**
* 根据绝对路径读取文件
* @param fileAbsolutePath 文件的绝对路径
* @return 读取结果VO
*/
public ReadFileResultVO readFileByAbsolutePath(String fileAbsolutePath){
//策略上下文
ReceiptStrategyContext receiptStrategyContext = new ReceiptStrategyContext();
// String fileAbsolutePath = "E:\\desktop\\一线楼市城市投资指南.docx";
IReadFileHandleStrategy readFileHandleStrategy =
ReadFileHandleStrategyFactory.getReadFileHandleStrategy(fileAbsolutePath);
receiptStrategyContext.setReadFileHandleStrategy(readFileHandleStrategy);
//执行策略
return receiptStrategyContext.handleReadFile(fileAbsolutePath);
}
}
- 策略上下文
ReadFileStrategyContext.java
import com.xxx.utils.factory.api.IReadFileHandleStrategy;
import com.xxx.vo.ReadFileResultVO;
/**
*
* @author wxz
* @date 2023.4.12
* @version 1.0.0
*/
public class ReadFileStrategyContext{
private IReadFileHandleStrategy readFileHandleStrategy;
/**
* 设置策略接口
* @param readFileHandleStrategy 策略标头
*/
public void setReadFileHandleStrategy(IReadFileHandleStrategy readFileHandleStrategy) {
this.readFileHandleStrategy = readFileHandleStrategy;
}
public ReadFileResultVO handleReadFile(String filePath){
if (readFileHandleStrategy != null) {
return readFileHandleStrategy.handleReadFile(filePath);
}
return new ReadFileResultVO();
}
}
- 文件类型枚举
UploadFileTypeEnum.java
/**
* 文件上传所支持的类型
*/
public enum UploadFileTypeEnum {
TXT(0, "TXT"),
ODF(1, "OFD"),
DOC(2, "DOC"),
DOCX(3,"DOCX"),
WPS(4,"WPS"),
PDF(5,"PDF");
private Integer value;
private String type;
UploadFileTypeEnum(Integer value, String type) {
this.value = value;
this.type = type;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
- 策略工厂
ReadFileHandleStrategyFactory.java
import com.xxx.common.exception.ServiceException;
import com.xxx.common.utils.StringUtils;
import com.xxx.constant.enums.UploadFileTypeEnum;
import com.xxx.utils.factory.api.IReadFileHandleStrategy;
import com.xxx.utils.factory.impl.ReadFileFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @Description: 根据文件类型调用读取方法的策略工厂
* @Auther: wxz
*/
public class ReadFileHandleStrategyFactory {
private static Map<String, IReadFileHandleStrategy> readFileHandleStrategyMap = new HashMap<>();;
/**
* 策略工厂,有扩展方法时,在工厂put进去
*/
static {
ReadFileFactory factory = new ReadFileFactory();
//ReadDOCFileStrategy 方法属于 ReadFileFactory类下面的非静态方法,因此需要第二次new即 factory.new ReadDOCFileStrategy(),而不能直接new
readFileHandleStrategyMap.put(UploadFileTypeEnum.DOC.getType(), factory.new ReadDOCFileStrategy());
readFileHandleStrategyMap.put(UploadFileTypeEnum.DOCX.getType(),factory.new ReadDOCXFileStrategy());
readFileHandleStrategyMap.put(UploadFileTypeEnum.ODF.getType(),factory.new ReadODFFileStrategy());
readFileHandleStrategyMap.put(UploadFileTypeEnum.WPS.getType(),factory.new ReadWPSFileStrategy());
readFileHandleStrategyMap.put(UploadFileTypeEnum.PDF.getType(),factory.new ReadPDFFileStrategy());
}
public static IReadFileHandleStrategy getReadFileHandleStrategy(String filePath){
new ReadFileHandleStrategyFactory();
String fileType = filePath.substring(filePath.lastIndexOf(".")).toUpperCase();
if (StringUtils.isEmpty(fileType))
throw new ServiceException("文件路径错误,请重新提交!", 500);
fileType = fileType.replace(".","").toUpperCase();
IReadFileHandleStrategy strategy = readFileHandleStrategyMap.get(fileType);
if (strategy == null)
throw new ServiceException("不支持的文件类型,请重新提交!", 500);
return strategy;
}
}
- 策略接口
IReadFileHandleStrategy.java
import com.xxx.vo.ReadFileResultVO;
/**
* 文件读取接口
* @author wxz
* @date 2023.4.12
* @version 1.0.0
*/
public interface IReadFileHandleStrategy {
ReadFileResultVO handleReadFile(String filePath);
}
- 策略接口的实现
ReadFileFactoryImpl.java
import com.xxx.common.exception.ServiceException;
import com.xxx.utils.ReadFileUtils;
import com.xxx.utils.factory.api.IReadFileHandleStrategy;
import com.xxx.vo.ReadFileResultVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* 根据绝对路径读取文件
* @author wxz
* @version 1.0.0
* @date 2023.4.12
*/
public class ReadFileFactoryImpl{
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
ReadFileUtils utils = new ReadFileUtils();
/**
* 根据绝对路径读取DOC文件
*/
public class ReadDOCFileStrategy implements IReadFileHandleStrategy {
@Override
public ReadFileResultVO handleReadFile(String filePath) {
try {
return utils.readDOC(filePath);
}
catch (IOException e) {
logger.error("文件读取失败,{}", e.getMessage());
throw new ServiceException("文件读取失败", 500);
}
}
}
/**
* 读取DOCX文件
*/
public class ReadDOCXFileStrategy implements IReadFileHandleStrategy {
@Override
public ReadFileResultVO handleReadFile(String filePath) {
try {
return utils.readDOCX(filePath);
}
catch (IOException e) {
logger.error("文件读取失败,{}", e.getMessage());
throw new ServiceException("文件读取失败", 500);
}
}
}
/**
* 读取ODF文件
*/
public class ReadODFFileStrategy implements IReadFileHandleStrategy {
@Override
public ReadFileResultVO handleReadFile(String filePath) {
return utils.readOFD(filePath);
}
}
/**
* 读取WPS文件
*/
public class ReadWPSFileStrategy implements IReadFileHandleStrategy {
@Override
public ReadFileResultVO handleReadFile(String filePath) {
return utils.readWPS(filePath);
}
}
/**
* 读取PDF文件
*/
public class ReadPDFFileStrategy implements IReadFileHandleStrategy {
@Override
public ReadFileResultVO handleReadFile(String filePath) {
try {
return utils.readPdf(filePath);
}
catch (Exception e) {
logger.error("文件读取失败,{}", e.getMessage());
throw new ServiceException("文件读取失败", 500);
}
}
}
}
- 执行流程大致如下所示
四、总结
经过上述重构,基本就能解决掉代码选择分支过多的问题。如果后续还需要读取更多的文件类型,则只需要:
- 实现
IReadFileHandleStrategy.java
中的handleReadFile()
接口 - 在
ReadFileHandleStrategyFactory
工厂中装配所扩展的方法即可(readFileHandleStrategyMap.put(文件类型枚举, factory.new 所调用的方法;
)