接口存在多个实现类时的动态调用
来源:互联网 发布:十堰房产每日成交数据 编辑:程序博客网 时间:2024/05/22 12:37
在之前做过的项目有这块的需求,也参考过网上大神们的设计方式,主要整理出一下两种方式供大家参考
使用Spring特性实现接口多实现类的动态调用
org.springframework.beans及org.springframework.context这两个包是spring IoC容器的基础,
其中重要的类有BeanFactory,BeanFactory是IoC容器的核心接口,其职责包括:实例化、定位、配置应用程序中的
对象及建立这些对象间的依赖关系。
ApplicationContext作为BeanFactory的子类,在Bean管理的功能上得到了很大的增强,也更易于与Spring AOP集成使用。
今天我们要讨论的并不是BeanFactory或者ApplicationContext的实现原理,而是对ApplicationContext的一种实际应用方式。问题的提出
在实际工作中,我们经常会遇到一个接口及多个实现类的情况,并且在不同的条件下会使用不同的实现类。从使用方式上看,有些类似SPI的用法,
但是由于SPI的使用并不是太方便,那么怎么办呢?我们可以借助ApplicationContext的getBeansOfType来实现我们需要的结果。首先我们看一下这个方法的签名
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
从上面的代码上我们可以看出来这个方法能返回一个接口的全部实现类(前提是所有实现类都必须由Spring IoC容器管理)。
接下来看看我们遇到的问题是什么?
“假设从A点到B点有多种交通方式,每种交通方式的费用不同,可以根据乘客的需要进行选择”(好吧,我承认这是个非常蹩脚的需求,
但是可以联想一下类似的需求,比如支付方式、快递公司,在页面提供几个选项,业务代码根据选项的不同选择不同的实现类实例进行调用)。实现
回到我们的例子,按照这个交通方式的需求,我们的设计如下:有一个交通方式的接口,接口有两个方式,一个查询费用、一个查询该交通方式的类型,同时,我们可以用一个枚举类型类标识交通类型。我们还需要一个工厂类来根据交通类型标识查找该交通类型的Bean实例,从而使用该实例,获得交通类型的详细信息及该交通类型的操作。
图片描述
代码如下:
接口:
/** * 交通方式 */public interface TrafficMode { /** * 查询交通方式编码 * @return 编码 */ TrafficCode getCode(); /** * 查询交通方式的费用,单位:分 * @return 费用 */ Integer getFee();}枚举:/** * 交通类型枚举 */public enum TrafficCode { TRAIN, BUS}接口有两个实现类:/** * 汽车方式 */@Componentpublic class BusMode implements TrafficMode { @Override public TrafficCode getCode() { return TrafficCode.BUS; } @Override public Integer getFee() { return 10000; }}/** * 火车方式 */@Componentpublic class TrainMode implements TrafficMode { @Override public TrafficCode getCode() { return TrafficCode.TRAIN; } @Override public Integer getFee() { return 9000; }}工厂类:/** * 交通方式工厂类 */@Componentpublic class TrafficModeFactory implements ApplicationContextAware { private static Map<TrafficCode, TrafficMode> trafficBeanMap; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, TrafficMode> map = applicationContext.getBeansOfType(TrafficMode.class); trafficBeanMap = new HashMap<>(); map.forEach((key, value) -> trafficBeanMap.put(value.getCode(), value)); } public static <T extends TrafficMode> T getTrafficMode(TrafficCode code) { return (T)trafficBeanMap.get(code); }}
验证有了上面的代码之后,我们一起通过单元测试来看一下效果,单元测试代码片段如下:
@Test public void testGetTrafficMode() { TrafficMode mode = TrafficModeFactory.getTrafficMode(TrafficCode.BUS); Assert.assertEquals(mode.getFee().intValue(), 10000); mode = TrafficModeFactory.getTrafficMode(TrafficCode.TRAIN); Assert.assertEquals(mode.getFee().intValue(), 9000); }
运行之后的结果呢?必然是通过。
自己实现适配器功能,但是需要每个实现类都实现InitializingBean类
还是以上述的例子来讲,每个类都重写afterPropertiesSet方法。直接上代码了
/** * 汽车方式 */@Componentpublic class BusMode implements TrafficMode , InitializingBean{ @Autowired public ITrafficModeFactory iTrafficModeFactory ; @Override public Integer getFee() { return 10000; } @Override public void afterPropertiesSet() { iTrafficModeFactory.register(TrafficCode.BUS,this); }}/** * 火车方式 */@Componentpublic class TrainMode implements TrafficMode , InitializingBean{ @Autowired public ITrafficModeFactory iTrafficModeFactory ; @Override public Integer getFee() { return 9000; } @Override public void afterPropertiesSet() { iTrafficModeFactory.register(TrafficCode.TRAIN,this); }}工厂类:/** * 交通方式工厂类 */@Componentpublic class TrafficModeFactory { private static Map<TrafficCode, TrafficMode> trafficBeanMap = new ConcurrentHashMap<>();; @Override public void register(String code, TrafficMode trafficMode) { trafficBeanMap.put(code, trafficMode); } public static <T extends TrafficMode> T getTrafficMode(TrafficCode code) { return (T)trafficBeanMap.get(code); }}
这里没有写工厂类的接口,写的是实现类,大家就自己实现下吧测试效果和第一种是一样的
当然实现方法还有很多种,不使用spring,使用抽象类也是可以的,只要可以找到对应关系,实现类可以实例化就可以了。
[1]:http://blog.csdn.net/a718515028/article/details/72457436
- 接口存在多个实现类时的动态调用
- 根据参数动态加载bean(一个接口多个实现的调用方法)
- 使用接口调用多个动态Module的同一方法
- c#中接口实现类的动态调用实现
- 使用Spring特性实现接口多实现类的动态调用
- 使用Spring特性实现接口多实现类的动态调用
- 使用Spring特性实现接口多实现类的动态调用
- 利用接口类实现对多个实现子类的初始化,并调用子类中的方法
- 存在多个网络接口时的多播发送与接收问题
- 定义一个接口,再定义类实现该接口,编写应用程序,调用接口中的 3 个方法,并将调用方法所得的结果输出。
- Web项目中使用java Struts2实现Zip、xml文件的动态创建和下载(Zip文件中动态存在多个xml文件)
- SNMP协议实现存在多个漏洞的攻击代码
- 接口、实现类和方法的调用
- 【单接口与多个实现类的注入处理】
- spring注解识别一个接口的多个实现类
- 类继承多个接口有相同的方法时,怎么办?(接口显式实现的作用)
- 实现接口的实现类,实现类方法调用
- 一个接口,多个实现类
- vue-router进行build无法正常显示路由页面
- CI框架中使用PHPExcel导出Excel文件
- JS中event对象的学习
- irq中断子系统
- Redis基本命令(二)
- 接口存在多个实现类时的动态调用
- 在eclipse中拉取github互联网上的代码
- nginx模块之ngx_http_proxy_module
- QT+MSVC2010编译32位ORACLE OCI驱动
- IO多路复用的网络通信
- STM32 FOC BLDC与PMSM的区别
- 百度地图简要demo--关键字查询,点定位
- dfs与bfs(1)
- Ubuntu16.04系统中配置ParaviewWeb5.3+Apache2