策略模式+单例模式+反射 实现PDA数据读取并根据相应类型存储

需求:PDA线下扫描入库/出库货物上传txt文件到服务器,出入库中间的每一步流程都会上传特定后缀的txt文件,我需要解析它们并存到数据库中
解决方案:想到之前公司老大在写地推代码的时候用到了策略模式,正好类似于这次需求,开干
首先写基础接口类

public interface FileReadWay {

  /**
   * 保存txt内容到数据库
   *
   * @Author:jiangruliang@finscm.com
   * @date: 2018/6/27/0027 13:56
   */
  int saveTxt(File file);

}

然后根据每个文件类型去建立相应的实现类并重写saveTxt方法,这里就不把具体实现类贴出,然后还要写一个枚举类(在获取读取文件类型后,根据枚举获取对应参数):
这里的枚举类里面的type是每个txt的类型,clazz是每个具体实现类的路径,在后面反射用到

public enum PdaFileHandleEnum {
  DJCY_FILE_READ("DJCY",
      "com.itonghui.biz.pdafilehandle.service.impl.DJCYFileRead"), DJEB_FILE_READ("DJEB",
      "com.itonghui.biz.pdafilehandle.service.impl.DJEBFileRead"), DJGB_FILE_READ("DJGB",
      "com.itonghui.biz.pdafilehandle.service.impl.DJGBFileRead"), DJRY_FILE_READ("DJRY",
      "com.itonghui.biz.pdafilehandle.service.impl.DJRYFileRead"), DJXH_FILE_READ("DJXH",
      "com.itonghui.biz.pdafilehandle.service.impl.DJXHFileRead"), THCY_FILE_READ("THCY",
      "com.itonghui.biz.pdafilehandle.service.impl.THCYFileRead"), THEB_FILE_READ("THEB",
      "com.itonghui.biz.pdafilehandle.service.impl.THEBFileRead"), THGB_FILE_READ("THGB",
      "com.itonghui.biz.pdafilehandle.service.impl.THGBFileRead"), THPG_FILE_READ("THPG",
      "com.itonghui.biz.pdafilehandle.service.impl.THPGFileRead"), THRY_FILE_READ("THRY",
      "com.itonghui.biz.pdafilehandle.service.impl.THRYFileRead"),;

  private String type;
  private String clazz;

  private PdaFileHandleEnum(String type, String clazz) {
    this.type = type;
    this.clazz = clazz;
  }

  public String type() {
    return type;
  }

  public String clazz() {
    return clazz;
  }

}
class FileReadContext {
  private static Map<String,String> strategyMap = new HashMap<>();
   //策略类:首先根据type去PdaFileHandleEnum找到对应类位置(clz),再通过反射获取其中saveText方法并执行
  static void excuteFileRead(String type, File file) {
    for (PdaFileHandleEnum t : PdaFileHandleEnum.values()){
      strategyMap.put(t.type(), t.clazz());
    }
    String class_path=strategyMap.get(type);
    try {
      //PdaFileHandleEnum通过反射将PdaFileHandleEnum中映射的类实例化
      Class clazz = Class.forName(class_path);
      //调用saveTxt方法传参file
      @SuppressWarnings("unchecked")
      Method excute = clazz.getDeclaredMethod("saveTxt", File.class);
      excute.invoke(clazz.newInstance(), file);
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
      e.printStackTrace();
    }
  }
}

这里先是将PdaFileHandleEnum中的type和clazz属性读到了一个strategyMap的HashMap中。
然后根据用户传入的type判断要实例化哪个类。
如果传入的是DJCY,则class_path为com.itonghui.biz.pdafilehandle.service.impl.DJCYFileRead。

通过Class.forName反射出该对象,并且执行其中的saveText方法。

这里的class_path就是PdaFileHandleEnum中的包路径了。

这样就实现替换switch{case}了。

因为每次调用excuteFileRead的时候都会重复将PdaFileHandleEnum中的type和clazz属性读到了一个strategyMap的HashMap中,这样是不合理的。

所以下面用了一个单例模式来解决这个问题。

新建一个FileReadSingleton

public class FileReadSingleton {
  private static FileReadSingleton instance=null;

  private FileReadSingleton(){
  }

  private static synchronized void syncInit() {
    if (instance == null) {
      instance = new FileReadSingleton();
    }
  }

  public static FileReadSingleton getInstance() {
    if (instance == null) {
      syncInit();
    }
    return instance;
  }

  private static Map<String,String> fileRead = new HashMap<>();
  static{
    for (PdaFileHandleEnum t : PdaFileHandleEnum.values())
      fileRead.put(t.type(), t.clazz());
  }
  public String fileRead(String type){
    return fileRead.get(type);
  }

}

同时改造FileReadContext类

class FileReadContext {
   //首先根据type去PdaFileHandleEnum找到对应类位置(clz),再通过反射获取其中saveText方法并执行
  static void excuteFileRead(String type, File file) {
    String clz = FileReadSingleton.getInstance().fileRead(type);
    try {
      //PdaFileHandleEnum通过反射将PdaFileHandleEnum中映射的类实例化
      Class clazz = Class.forName(clz);
      //调用saveTxt方法传参file
      @SuppressWarnings("unchecked")
      Method excute = clazz.getDeclaredMethod("saveTxt", File.class);
      excute.invoke(clazz.newInstance(), file);
    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
      e.printStackTrace();
    }
  }
}

完成。
感想:其实刚开始只是用策略模式实现了需求,后面由于switch{case}过多看的总是让人不爽于是找到了度娘,度娘告诉我反射能够解决,于是搜着找到了一篇博客,其实本篇博客思路几乎来自于该博客,感谢。

https://blog.csdn.net/u012840660/article/details/80484342

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值