实际项目中,中台系统会对外提供一个“通用”的接口,例如绑卡接口,而实际上,中台系统可能对接多家渠道,有些渠道需要进行个性化处理。
但是即使对接不同渠道(银行),但处理逻辑本质上是相同的,那么我们就可以将公共的代码抽取出来,子类实现个性化的扩展。——而它本质上是模板方法模式。
当然,我们的想法是这样的:
请求方式.png公共服务:大多数银行的处理逻辑;
xx银行服务:个性化处理xx银行的逻辑;
请求报文中可能存在商户号字段,而根据商户号,可以在缓存中获取该商户的银行标识。根据银行标识去Spring单例池中获取对应的Service,来完成业务处理。
而枚举类,相当于一个数据字典,会保存某个接口下所有的类型、描述等信息。枚举类相当于工厂模式。根据枚举值的不同获取不同的service对象。
public enum OpenAuthenServiceEnum {
/**
* 缺省情况下的Bean
*/
DEFAULT("openAuthenService", OpenAuthenService.class, "通用绑卡业务接口"),
/**
* 子类特有Bean对象
*/
MZ("XxopenAuthenService", XXOpenAuthenService.class, "XX业务-绑卡接口");
/**
* key:枚举值name,即业务标识。
* value:枚举值对象。
*/
private static Map<String, OpenAuthenServiceEnum> mapping = new HashMap<>(16);
/**
* key: 枚举值name,即业务标识
* value:bean对象
*/
private static Map<String, OpenAuthenService> serviceCache = new ConcurrentHashMap<>(16);
static {
for (OpenAuthenServiceEnum authenServiceEnum : values()) {
mapping.put(authenServiceEnum .name(), authenServiceEnum);
}
}
/**
* Bean 名字,父类一般首字母小写,子类首字母大写。
* 可以在{@code @service("aa")}手动指定BeanName
*/
private String beanName;
/**
* Bean 类型: 用于在Spring容器中获取某类Bean
*/
private Class<? extends OpenAuthenService> beanType;
/**
* 描述,用于打印日志
*/
private String desc;
OpenAuthenServiceEnum(String beanName, Class<? extends OpenAuthenService> beanType, String desc) {
this.beanName = beanName;
this.beanType = beanType;
this.desc = desc;
}
public String getBeanName() {
return beanName;
}
public Class<? extends OpenAuthenService> getBeanType() {
return beanType;
}
public String getDesc() {
return desc;
}
/**
* 根据枚举对象名 获取泛枚举值对象(线程安全)
*
* @param enumName 枚举值的名字,不区分大小写
* @return 若上送参数为null,则返回null,
* 若上送的业务标识在mapping缓存,返回对应的枚举值对象。
* 否则返回缺省 枚举值对象。
*/
public static OpenAuthenServiceEnum resolve(String enumName) {
return enumName != null ? mapping.getOrDefault(enumName.toUpperCase(), DEFAULT) : null;
}
/**
* 泛型对象获取 Bean类(线程安全)
* 下列代码等效于
* OpenAuthenService service=serviceCache.get(this.getBeanName());
* if(service==null){
* synchronized(this){
* service=serviceCache.get(this.getBeanName())
* if(service==null){
* service=SpringUtil.getBean(this.getBeanName(),this.getBeanType());
* serviceCache.put(this.getBeanName(),service);
* }
* }
* }
*
* @return Bean对象
*/
public OpenAuthenService getBean() {
return serviceCache.computeIfAbsent(this.name(),
K -> SpringUtil.getBean(this.getBeanName(), this.getBeanType()));
}
}
使用方式:
OpenAuthenServiceEnum bz = OpenAuthenServiceEnum.resolve("Bz");
if(bz==null){
throw new RuntimeException("业务参数不能为null");
}
//获取到对应的service,可以完成个性化的调用。
OpenAuthenService bzBean = bz.getBean();
这样的话,例如项目的可维护性和可扩展性,当然枚举类中还可以使用其他属性来完成个性化的配置。
注:Spring中Bean名字一般是简写的类名,并且首字母小写,但是Bean的子类首字母要大写。
网友评论