先来看几段代码
从 解码-> 处理 -> 编码,你会发现我们使用了很多的if或者case,尤其是这个handler处理这一步代码量非常多,还是多功能的耦合在一起,非常不利于业务的拓展以及维护。
略懂设计模式的应该都懂,需要使用设计模式中的工厂模式来优化。
创建对应的工厂,使用hashmap集合来存储
编码器和解码器工厂(消息编码工厂)
Handler处理器工厂
需要获取的话直接使用 map.get来获取对应的value,看这个handlerMap,每个命令需要执行的具体业务就交给一个类来处理,而不是耦合在同一个handler中。
看现在优化完成后,handdler的类一下就简洁了。
本以为优化到这已经优化完成了,非常完美!!!
但是想要达到架构师的水平还远远不够的,你想想,每次添加新的任务,我都需要执行3步,decoderMap中添加 -> 添加处理器 -> encoderMap中添加,这给用户的体验不是很好哦,有没有什么可以我只要 一步到位 的方法呢?
当然有,只不过对技术水平要求比较高一些。我在初始化的时候 通过反射的方式将一些需要的东西自动添加到 deconderMap 和 encoderMap 当中。
private static void autoInit(Class clazz){
Class<?>[] declaredClasses = clazz.getDeclaredClasses();
for (Class<?> innerClazz :declaredClasses){
if(!GeneratedMessageV3.class.isAssignableFrom(innerClazz)){
continue;
}
String simpleName = innerClazz.getSimpleName();
simpleName = simpleName.toLowerCase();
System.out.println(simpleName);
for (GameMsgProtocol.MsgCode msgCode : GameMsgProtocol.MsgCode.values()) {
String name = msgCode.name();
name = name.replaceAll("_", "").toLowerCase();
if(!name.startsWith(simpleName)){
continue;
}
try {
Object defaultInstance = innerClazz.getDeclaredMethod("getDefaultInstance").invoke(innerClazz);
decoderMap.put(msgCode.getNumber(), (GeneratedMessageV3) defaultInstance);
//不要误写成 innerClazz.getClass()
encoderMap.put(innerClazz, msgCode.getNumber());
logger.info(innerClazz.getName() + " <===> " + msgCode.getNumber());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
直接在 GameMsgProtocol 中获取 里面的内部类,通过遍历筛选,保存符合业务需求的数据到map中。
看现在只需要调用此函数就ok了,以后添加新的需求,就不需要在map.put如此之麻烦了。
遇到的问题:
实例.getClass() 获取实例的类型类
对象.class 获取类对象的类型类
Class<?> clazz 是类对象类型类
由于这两个概念的误解导致encoderMap自动注入的失败
总结:
这个思想非常的棒,如果我们想要添加某些业务的话,只需要在直接添加 new Handler,在handlerMapz中添加handler就可以了,方便简洁低耦合,以后哪个功能出问题了直接找对应的Handler类就OK了。
但是这个hadlerMap还是可以优化的哦!可以添加注解,这样就可以直接帮助我们注入到对应的handlerMap中,加油,一步一步来!