zoukankan      html  css  js  c++  java
  • java设计模式之监听者

    一、前言

    监听者并不在23种设计模式之中,有点类似于观察者模式,但又不完全相同。

    实际项目中,特别在与用户交互的前端设计或UI设计中使用的非常广泛。

    最近的项目中需要加载分析excel中的数据并存入DB,在easyexcel的代码中也运用了监听者模式。

    写了一个简单的demo,来理解它的工作原理。

    之前很多excel分析工具Apache poi,jxl等,是将整个文件读到内存进行解析的,所以非常耗内存。easyexcel不同,他是一行一行进行解析的,所以即便是几百万行的excel文件,也完全能够搞定。

    这个时候就会遇到一个问题,我们一行一行解析,数据放在哪?还是内存里吗?那就失去了一行一行解析的意义。

    但easyexcel也不知道解析完之后,用户到底要干什么,那之后把这个问题抛给使用者。

    二、Listener

    easyexcel不知道解析完数据,使用者要干什么,因此他设计并让分析对象持有了一个Listener接口

    接口很简单,只有两个方法:

    1.invoke()方式是这一行解析完了,我给你封装成了T对象,你要不要干点啥?

    2.doAfterAllAnalysed()方法是整个文件都解析完了,你爱干啥就干点啥吧。

    public interface Listener<T> {
        void invoke(T t);
        void doAfterAllAnalysed();
    }

    三、事件

    有监听者就有被监听的事件,在excel解析这个过程中,事件显然就是文件的每一行被解析得到的对象T t。

    产生事件的自然就是excel分析器,下面是分析器的实现

    分析器的输入是一个文件,因此一定要持有一个File对象,当然InputStream也可以

    每一行需要被解析成一个java对象,构造对象需要相应的Class,所以也需要传入一个Class<T>对象

    每解析完以后都需要通知监听者,因此还需要持有监听者对象

    核心的实现是doAnalysis()方法,每解析成功一行,就调用监听者的invoke方法,所有行解析完了调用doAfterAllAnalysed()方法。

    public class ExcelAnalyzer<T> {
    
        private File file;
        private Class<T> clazz;
        private Listener<T> listener;
    
        public ExcelAnalyzer<T> setListener(Listener<T> listener) {
            if (listener != null) {
                this.listener = listener;
            }
            return this;
        }
    
        void doAnalysis() throws FileNotFoundException {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            reader.lines().forEach(line -> {
                T t = process(line);
                if (this.listener != null) {
                    this.listener.invoke(t);
                }
            });
            if (this.listener != null) {
                this.listener.doAfterAllAnalysed();
            }
        }
    
        /**
         * 实际要处理更多类型
         *
         * @param line
         * @return
         */
        public T process(String line) {
            T t = null;
            try {
                t = clazz.newInstance();
                String[] split = line.split(",");
                Field[] declaredFields = clazz.getDeclaredFields();
                int length = declaredFields.length;
                for (int i = 0; i < length; i++) {
                    Field field = declaredFields[i];
                    field.setAccessible(true);
                    if (field.getType().getName().equals(Integer.class.getName())) {
                        field.set(t, Integer.valueOf(split[i]));
                    } else {
                        field.set(t, split[i]);
                    }
                }
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
            return t;
        }
    
        public ExcelAnalyzer<T> read(File file, Class<T> clazz) {
            this.file = file;
            this.clazz = clazz;
            return this;
        }
    }

    四、主程序

    在主程序执行之前,还需要定义一个java对象类User,它是每一行对应的java对象,这里我们简单定义一下,当然实际的对象可能会更复杂。

    @Data
    public class User {
        private String name;
        private Integer age;
    
    }

    主程序实现:

    主程序模仿了easyExcel的实现,看起来还是很像的。

    public class Test {
        public static void main(String[] args) throws FileNotFoundException {
            File file = new File("C:\Users\G007112\Desktop\excel.txt");
            ExcelAnalyzer<User> userExcelAnalyzer = new ExcelAnalyzer<User>().read(file,User.class).setListener(new Listener<User>() {
                @Override
                public void invoke(User user) {
                    System.out.format("I get line=%s", user);
                    System.out.println();
                }
                @Override
                public void doAfterAllAnalysed() {
                    System.out.println("Excel file analysis success!!!");
                }
            });
            userExcelAnalyzer.doAnalysis();
        }
    }

    当然只是想执行一遍程序,啥也不干也是可以的,分析器不传入Listener也完全可以很健壮的运行。只是没有啥意义而已。

    以上代码是模仿了easyExcel,源代码中的实现更复杂。

    输出:

    I get line=User(name=line, age=1)
    I get line=User(name=line, age=2)
    I get line=User(name=line, age=3)
    I get line=User(name=end, age=4)
    Excel file analysis success!!!
  • 相关阅读:
    上传代码到github
    AFN多文件进度下载
    NSURLSession各文件关系
    H5动静分离
    iOS设备获取总结
    iOS与JS开发交互总结
    iOS11 push控制器tabbar上移问题
    解决iOS11 UIScrollView下移问题
    关于react16.4——错误边界
    关于react16.4——上下文Context
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/15157423.html
Copyright © 2011-2022 走看看