美文网首页java 设计Design Pattern 设计模式-收藏篇
枚举类+模板方法模式—动态调用接口

枚举类+模板方法模式—动态调用接口

作者: 小胖学编程 | 来源:发表于2020-01-13 19:10 被阅读0次

实际项目中,中台系统会对外提供一个“通用”的接口,例如绑卡接口,而实际上,中台系统可能对接多家渠道,有些渠道需要进行个性化处理。

但是即使对接不同渠道(银行),但处理逻辑本质上是相同的,那么我们就可以将公共的代码抽取出来,子类实现个性化的扩展。——而它本质上是模板方法模式

当然,我们的想法是这样的:

请求方式.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的子类首字母要大写。

相关文章

  • 枚举类+模板方法模式—动态调用接口

    实际项目中,中台系统会对外提供一个“通用”的接口,例如绑卡接口,而实际上,中台系统可能对接多家渠道,有些渠道需要进...

  • 设计模式

    策略模式 接口 模板方法模式 抽象类 代理模式 接口

  • JS设计模式之模板模式

    [#]什么是模板模式? 模板模式是:抽象父类定义了子类需要重写的相关方法。并且这些方法,仍然是通过父类方法调用的。...

  • 14.动态代理

    代理模式 java动态代理:利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandle...

  • 好程序员web前端教程分享js模板模式

    什么是模板模式? 模板模式是抽象父类定义了子类需要重写的相关方法。而这些方法,仍然是通过父类方法调用的。根据描述,...

  • Java篇-枚举的使用

    一 : 自定义枚举类 枚举类调用 二 : 使用enum关键字定义枚举类 让枚举类实现接口: 可以让不同的枚举类的对...

  • iOS动态调用类方法

    iOS动态调用类方法(不带参数) iOS动态调用类方法(带参数) iOS动态调用类方法(有返回值) 优点 弱化连接...

  • 代理模式

    代理模式是Java常用的设计模式,由代理类和委托类以及它们共同实现的接口组成;客户端通过调用代理类的方法间接调用委...

  • 枚举--java24(02/17/2016)

    如何自定义枚举类如何使用enum定义枚举类、枚举类的主要方法实现接口的枚举类 JDK1.5之前需要自定义枚举类JD...

  • 动态代理

    动态代理实现过程 定义接口 获取代理实例并调用实力上的方法 动态代理会生成接口或者实现接口的类的实例 该实例并非静...

网友评论

    本文标题:枚举类+模板方法模式—动态调用接口

    本文链接:https://www.haomeiwen.com/subject/kxdkactx.html