抽象工厂模式
背景
(根据生产环境虚拟)目前又M个厂商,每个厂商又有N个产品,现在需要获取不同厂商的不同产品的详细信息(可以理解为级联查询获取详细信息)
考虑
- 使用if-else或switch-case方案
- 单个文件代码过长,
- 不同产品需要的配置信息类(class对象)相同但又不是同一个配置信息类,会出现很多全类名对象的代码
- 工厂方法
- 没有共同父类,返回Object对象还需要再进行instanceof判断,两边需要同时修改,麻烦
思考
- 先写一个对外统一暴露接口(IGeneralService),所有对外服务都通过该接口查询(外观模式?)
- IGeneralService接口根据不同厂商获取对应服务(IProviderService)(工厂模式?)
- IProviderService接口根据不同产品获取对应服务(IProductService)(工厂模式?)
措施
-
外观模式肯定是需要的,避免外层调用的麻烦
-
是否直接使用工厂模式
- 不同厂商、产品对外提供的服务都是一样的,即各自有一个共同父接口
- 需要考虑后续扩展。
最开始是考虑使用工厂模式的,理由是简单,写起来比较快,缺点就是扩展时需要改工厂类。
注意:前面说过使用的是Spring框架,Spring框架的两大特点之一就是IOC,容器中存储了bean对象。
那么我们就可以考虑如何通过IOC容器获取到我们对应的bean对象了,即使用接口和bean名称获取实际服务实现类,一种变相抽象工厂(算是吧?)
代码实现
- 为了查找服务及提供对外级联查询接口,准备注解类(通过查询注解即可知道有多少厂商和产品)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Provider {
/**
* 厂商名称,前端页面展示信息
* @return
*/
@AliasFor("label")
String name() default "";
/**
* 厂商名称,前端页面展示信息
* @return
*/
@AliasFor("name")
String label() default "";
/**
* 厂商值,前后端传递字段
* @return
*/
String value();
/**
* 厂商值,前后端传递字段
* @return
*/
String value();
/**
* 用于排序,根据实际情况考虑
* @return
*/
int order() default 0;
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Product {
/**
* 产品名称,用于页面展示
* @return
*/
@AliasFor("label")
String name() default "";
/**
* 产品名称,用于页面展示
* @return
*/
@AliasFor("name")
String label() default "";
/**
* 产品值,用于前后端查询
* @return
*/
String value();
/**
* 用于排序,根据实际情况考虑
* @return
*/
int order() default 0;
}
- 需要一个容器工具类,用于获取bean对象
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
private static final Logger logger = LoggerFactory.getLogger(SpringUtil.class);
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
/**
* 获取applicationContext
*/
public static ApplicationContext getApplicationContext