Java 关于策略模式+简单工厂模式下的思考
导读#
最近在做公司一个消息网关的服务,包括:短信、微信、邮件等,所有请求通过一个入口,方便接口的管理(记录日志、接口限流白名单啥的)。如何写这个接口呢,还有为了以后扩展,对接过短信、微信、公众号的童鞋大概都了解,首先定义一个模板,然后后台传入json,替换模板中的值,然后发送。设计框架大概思路是这样的
- 第一层:通过策略模式,选择出具体的发送类型,比如:短信、微信、邮件。。。。。
- 第二层:再次通过策略模式,选择出具体的第三方平台,比如短信平台:阿里云、腾讯云、华为云。。。。。。
- 第三层:通过一个简单的工厂,选择出具体的模板,然后发送出去
第一二层,以后可能会扩展出2、3家第三方平台,使用策略模式还是可以接受的,但是到了第三层的话,可能会出现一二十个模板,这样子的话,会出现一大堆if else等等(写过简单工厂的都清楚),然后自己手动封装一个工具类,获取一个类下的所有子类,然后通过一个字段创建对象,这里我做了一个优化,找到的值,我会先放到一个Map中,第二次请求来的时候,先去Map中查询下,是否有值,有值的话,直接调用,没有值的话,才会去重新找一遍,这样子性能也得到了提高
项目结构#
工具类#
package com.ybchen.messagegateway; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * @ClassName:TestMain * @Description:TODO * @Author:chenyb * @Date:2020/12/1 9:19 上午 * @Versiion:1.0 */ public class TestMain { public static void main(String[] args) throws Exception { System.out.println("接口实现类:"); for (Class<?> c : getAllAssignedClass(AbsClassA.class)) { if (c.getName().contains("D")){ AbsClassA obj =(AbsClassA) c.newInstance(); obj.speak(); } System.out.println(c.getName()); } System.out.println("子类:"); for (Class<?> c : getAllAssignedClass(AbsClassA.class)) { System.out.println(c.getName()); } } /** * 获取同一路径下所有子类或接口实现类 * * @param intf * @return * @throws IOException * @throws ClassNotFoundException */ public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws Exception { List<Class<?>> classes = new ArrayList<>(); for (Class<?> c : getClasses(cls)) { if (cls.isAssignableFrom(c) && !cls.equals(c)) { classes.add(c); } } return classes; } /** * 取得当前类路径下的所有类 * * @param cls * @return * @throws IOException * @throws ClassNotFoundException */ public static List<Class<?>> getClasses(Class<?> cls) throws Exception { String pk = cls.getPackage().getName(); String path = pk.replace('.', '/'); ClassLoader classloader = Thread.currentThread().getContextClassLoader(); URL url = classloader.getResource(path); return getClasses(new File(url.getFile()), pk); } /** * 迭代查找类 * * @param dir * @param pk * @return * @throws ClassNotFoundException */ private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException { List<Class<?>> classes = new ArrayList<>(); if (!dir.exists()) { return classes; } for (File f : dir.listFiles()) { if (f.isDirectory()) { classes.addAll(getClasses(f, pk + "." + f.getName())); } String name = f.getName(); if (name.endsWith(".class")) { classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6))); } } return classes; } }

package com.ybchen.messagegateway; /** * @ClassName:AbsClassA * @Description:TODO * @Author:chenyb * @Date:2020/12/1 9:16 上午 * @Versiion:1.0 */ public abstract class AbsClassA { public abstract void speak(); }

package com.ybchen.messagegateway; /** * @ClassName:ClassB * @Description:TODO * @Author:chenyb * @Date:2020/12/1 9:16 上午 * @Versiion:1.0 */ public class ClassB extends AbsClassA { @Override public void speak() { System.out.println("BBBBBBB"); } }

package com.ybchen.messagegateway; /** * @ClassName:ClassC * @Description:TODO * @Author:chenyb * @Date:2020/12/1 9:16 上午 * @Versiion:1.0 */ public class ClassC extends AbsClassA{ @Override public void speak() { System.out.println("CCC"); } }

package com.ybchen.messagegateway.de; import com.ybchen.messagegateway.AbsClassA; /** * @ClassName:ClassD * @Description:TODO * @Author:chenyb * @Date:2020/12/1 9:17 上午 * @Versiion:1.0 */ public class ClassD extends AbsClassA { @Override public void speak() { System.out.println("ddd"); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2019-12-01 springmvc: No converter found for return value of type