美文网首页Android知识Android开发Android技术知识
打造一个专注Java假数据的JBMock

打造一个专注Java假数据的JBMock

作者: Android开发哥 | 来源:发表于2017-05-17 16:59 被阅读374次

    前言

    两个月前写过一篇文章基于Django设计的Restful MockServer,是基于网络的。很多人都觉得思路不错,但是主要是太麻烦了。本篇博文就根据Java开发一个假数据生成器,称为JBMock

    Github地址

    主要功能

    • 1、提供同步、异步获取数据

    • 2、异步获取数据提供线程切换

    原理图

    原理图
    • 1、使用反射,获取UserEntity的属性和对应注解(Type注解)

    • 2、获取注解里面的值,然后使用TypeParser解析注解值,然后设置到对应的属性上

    • 3、使用ThreadDispatcher完成回调

    代码分析

    包结构

    包结构

    代码

    Type注解

    package com.august1996.anno;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Type {
        String value();
    }
    

    这个注解的意义在于我们给某个属性加上这个注解,然后根据类型去给属性赋值,例如value为username时,那么这个属性就会被赋上小明、小红、小花等值

    TypeParser类型解析器

    package com.august1996.core;
    
    public interface TypeParser {
        Object parser(String type);
    }
    

    该接口的作用是解析Type注解的value,返回对应的值

    OnMockedCallback回调

    package com.august1996.callback;
    
    import java.util.ArrayList;
    
    public interface OnMockedCallback<T> {
        void onMocked(ArrayList<T> listEntity);
    }
    

    当异步模拟数据完成时,该回调带着结果被执行

    ThreadDispatcher线程切换

    package com.august1996.thread;
    
    import java.util.ArrayList;
    
    import com.august1996.callback.OnMockedCallback;
    
    public interface ThreadDispatcher {
        <T> void dispatcher(ArrayList<T> value, OnMockedCallback<T> callback);
    }
    

    该接口完成回调时的线程切换,本项目是JavaSDK的,如果接入Android时,只需要继承自该接口使用Handler就能完成主线程切换

    DefaultDispatcher分配默认线程

    package com.august1996.thread;
    
    import java.util.ArrayList;
    
    import com.august1996.callback.OnMockedCallback;
    
    public class DefaultDispatcher implements ThreadDispatcher {
    
        @Override
        public <T> void dispatcher(ArrayList<T> value, OnMockedCallback<T> callback) {
            if (callback != null) {
                callback.onMocked(value);
            }
        }
    
    }
    

    该类是最简单的ThreadDispatcher,如果需要在Android中切换主线程,只需要继承ThreadDispatcher,然后使用Handler切换回主线程就OK了

    DispatcherHolder管理类

    package com.august1996.thread;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class DispatcherHolder {
    
        private static final Map<Class<? extends ThreadDispatcher>, ThreadDispatcher> sMap;
    
        static {
            sMap = new HashMap<>();
            register(new DefaultDispatcher());
        }
    
        public static void register(ThreadDispatcher dispatcher) {
            sMap.put(dispatcher.getClass(), dispatcher);
        }
    
        public static void unregister(Class<? extends ThreadDispatcher> clazz) {
            sMap.remove(clazz);
        }
    
        public static ThreadDispatcher get(Class<? extends ThreadDispatcher> clazz) {
            return sMap.get(clazz);
        }
    
    }
    

    该类的作用是管理不同类型的ThreadDispatcher,可以通过注册不同的ThreadDispatcher,使JBMock可以调用其他自己编写的ThreadDispatcher

    ValueHolder类型数据管理器

    package com.august1996.parser;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Random;
    
    public class ValueHolder {
        private static final Map<String, List<Object>> sMap = new HashMap<String, List<Object>>();
        private static final Random sRandom = new Random();
    
        public static void register(String type, Object... value) {
            List<Object> list = sMap.get(type);
            if (list == null) {
                list = new ArrayList<Object>();
                sMap.put(type, list);
            }
            list.addAll(Arrays.asList(value));
        }
    
        public static void unregister(String type) {
            sMap.remove(type);
        }
    
        public static void clear() {
            sMap.clear();
        }
    
        static Object get(String type) {
            List<Object> list = sMap.get(type);
            if (list != null && !list.isEmpty()) {
                return list.get(sRandom.nextInt(list.size()));
            }
            return null;
        }
    }
    

    该类负责管理Type注解对应的数据,例如如果想要当属性的Type的value为username时,JBMock就会给这个属性赋值小明、小红、小花等内容,那么就需要register("username","小明","小红","小花")

    HolderParser解析器

    package com.august1996.parser;
    
    import com.august1996.core.TypeParser;
    
    public class HolderParser implements TypeParser {
    
        @Override
        public Object parser(String type) {
            return ValueHolder.get(type);
        }
    
    }
    

    该类为默认的Parser之一,结合Type注解ValueHolder根据类型解析数据

    MockRunnable异步任务

    package com.august1996.core;
    
    import java.util.ArrayList;
    
    import com.august1996.callback.OnMockedCallback;
    import com.august1996.thread.DispatcherHolder;
    import com.august1996.thread.ThreadDispatcher;
    
    public class MockRunnable<T> implements Runnable {
    
        private Class<T> clazz;
        private int size;
        private int delay;
        private OnMockedCallback<T> callback;
        private Class<? extends ThreadDispatcher> threadDispatch;
    
        public MockRunnable(Class<T> clazz, int size, int delay, Class<? extends ThreadDispatcher> threadDispatch,
                OnMockedCallback<T> callback) {
            super();
            this.delay = delay;
            this.clazz = clazz;
            this.callback = callback;
            this.size = size;
            this.threadDispatch = threadDispatch;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(delay);
                ArrayList<T> listEntity = Factory.getListEntity(clazz, size);
                DispatcherHolder.get(threadDispatch).dispatcher(listEntity, callback);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    Factory数据生产类

    package com.august1996.core;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    
    import com.august1996.anno.Type;
    import com.august1996.parser.DefaultParser;
    import com.august1996.parser.HolderParser;
    
    public class Factory {
        static {
            mParser = new HashMap<>();
            initDefautParser();
        }
        private static Map<Class<? extends TypeParser>, TypeParser> mParser;
    
        /**
         * 获取多个Entity
         * 
         * @param cls
         *            Entity的类
         * @param size
         *            Entity的数量
         * @return
         */
        static <T> ArrayList<T> getListEntity(Class<T> cls, int size) {
            ArrayList<T> result = new ArrayList<T>();
            for (int i = 0; i < size; i++) {
                result.add(getEntity(cls));
            }
            return result;
        }
    
        /**
         * 获取单个Entity
         * 
         * @param cls
         * @return
         */
        static <T> T getEntity(Class<T> cls) {
            T obj = null;
    
            try {
                obj = cls.newInstance();
    
                Field[] declaredFields = cls.getDeclaredFields();
                for (Field field : declaredFields) { // 获取Entity类的所有属性
                    field.setAccessible(true);
                    Annotation[] annotations = field.getAnnotations(); // 获取属性的注解
                    for (Annotation anno : annotations) {
                        if (anno instanceof Type) {
                            for (Map.Entry<Class<? extends TypeParser>, TypeParser> parser : mParser.entrySet()) {
                                Object value = parser.getValue().parser(((Type) anno).value()); // 获取到Type注解,使用TypeParser去解析类型
                                if (value != null) {
                                    field.set(obj, value);
                                }
                            }
                        }
                    }
                }
    
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return obj;
        }
    
        /**
         * 初始化默认TypeParser
         */
        private static void initDefautParser() {
            addParser(new HolderParser());
        }
    
        public static void addParser(TypeParser typeParser) {
            mParser.put(typeParser.getClass(), typeParser);
        }
    
        public static TypeParser removeParser(Class<? extends TypeParser> clazz) {
            return mParser.remove(clazz);
        }
    
        public static void clearParser() {
            mParser.clear();
            initDefautParser();
        }
    }
    

    该类主要是用来产生数据

    JBMock核心类

    package com.august1996.core;
    
    import java.util.ArrayList;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    import com.august1996.callback.OnMockedCallback;
    import com.august1996.thread.ThreadDispatcher;
    
    public class JBMock {
        private static final JBMock sInstance = new JBMock();
    
        public static JBMock getInstance() {
            return sInstance;
        }
    
        private JBMock() {
            mExecutors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        }
    
        private ExecutorService mExecutors;
    
        public <T> ArrayList<T> syncGet(Class<T> cls, int delay, int size) {
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Factory.getListEntity(cls, size);
        }
    
    
        public <T> void asyncGet(Class<T> cls, int delay, int size, Class<? extends ThreadDispatcher> threadDispatcherCls,
                OnMockedCallback<T> callback) {
            mExecutors.submit(new MockRunnable<T>(cls, size, delay, threadDispatcherCls, callback));
        }
    
    
    }
    

    使用

    新建一个UserEntity

    package com.august1996.test;
    
    import com.august1996.anno.Type;
    import com.august1996.parser.DefaultType;
    
    public class UserEntity {
        @Type("username")
        public String username;
        @Type("icon")
        public String icon;
        @Type("gender")
        public int gender;
        @Type(DefaultType.NOW_TIMESTAMP)
        public long regTime;
    
        @Override
        public String toString() {
            return "UserEntity [username=" + username + ", icon=" + icon + ", gender=" + gender + ", regTime=" + regTime
                    + "]";
        }
    
    }
    

    测试代码

    package com.august1996.test;
    
    import java.util.ArrayList;
    
    import com.august1996.callback.OnMockedCallback;
    import com.august1996.core.JBMock;
    import com.august1996.parser.ValueHolder;
    import com.august1996.thread.DefaultDispatcher;
    
    public class TestDemo {
        public static void main(String[] args) {
            ValueHolder.register("username", "小明", "小红");
            ValueHolder.register("username", "小花");
    
            ValueHolder.register("icon", "http://www.baidu.com/1.jpg", "http://www.baidu.com/2.jpg");
            ValueHolder.register("icon", "http://www.baidu.com/3.jpg");
    
            ValueHolder.register("gender", 1);
            ValueHolder.register("gender", 0);
    
            ArrayList<UserEntity> list = JBMock.getInstance().syncGet(UserEntity.class, 3000, 10);
            for (UserEntity entity : list) {
                System.out.println(entity.toString());
            }
    
            JBMock.getInstance().asyncGet(UserEntity.class, 3000, 5, DefaultDispatcher.class,
                    new OnMockedCallback<UserEntity>() {
    
                        @Override
                        public void onMocked(ArrayList<UserEntity> listEntity) {
                            System.out.println(Thread.currentThread().getName());
                            for (UserEntity entity : listEntity) {
                                System.out.println(entity.toString());
                            }
                        }
                    });
    
        }
    }
    

    输出

    pool-1-thread-1
    UserEntity [username=小花, icon=http://www.baidu.com/2.jpg, gender=0, regTime=1495010339777]
    UserEntity [username=小明, icon=http://www.baidu.com/3.jpg, gender=1, regTime=1495010339779]
    UserEntity [username=小明, icon=http://www.baidu.com/3.jpg, gender=1, regTime=1495010339779]
    UserEntity [username=小红, icon=http://www.baidu.com/3.jpg, gender=0, regTime=1495010339779]
    UserEntity [username=小花, icon=http://www.baidu.com/2.jpg, gender=1, regTime=1495010339779]
    

    DefaultType.NOW_TIMESTAMP是什么

    这是我们自定义的一个TypeParser,我们使用Factory.addParser添加就OK啦。

    DefaultParser

    package com.august1996.parser;
    
    import com.august1996.core.TypeParser;
    
    public class DefaultParser implements TypeParser {
    
        @Override
        public Object parser(String type) {
            if (DefaultType.NOW_TIMESTAMP.equals(type)) {
                return System.currentTimeMillis();
            }
            return null;
        }
    }
    

    DefaultType

    package com.august1996.parser;
    
    public class DefaultType {
        public static final String NOW_TIMESTAMP = "jb_now";
    }
    

    可自行扩展的地方

    需要更多的扩展,实现ThreadDispatcher和TypeParser即可。

    相关文章

      网友评论

        本文标题:打造一个专注Java假数据的JBMock

        本文链接:https://www.haomeiwen.com/subject/lhgdxxtx.html