设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 创业者 数据 手机
当前位置: 首页 > 服务器 > 搭建环境 > Unix > 正文

刚来的大神彻底干掉了代码中的if else...(3)

发布时间:2019-12-06 01:45 所属栏目:119 来源:站长网
导读:privatestaticMapString,UserPayServiceservices=newConcurrentHashMapString,UserPayService(); publicstaticUserPayServicegetByUserType(Stringtype){ returnservices.get(type); } publicstaticvoidregister(St

    private static Map<String,UserPayService> services = new ConcurrentHashMap<String,UserPayService>(); 

 

    public  static UserPayService getByUserType(String type){ 

        return services.get(type); 

    } 

 

    public static void register(String userType,UserPayService userPayService){ 

        Assert.notNull(userType,"userType can't be null"); 

        services.put(userType,userPayService); 

    } 

这个 UserPayServiceStrategyFactory 中定义了一个 Map,用来保存所有的策略类的实例,并提供一个 getByUserType 方法,可以根据类型直接获取对应的类的实例。还有一个 Register 方法,这个后面再讲。

有了这个工厂类之后,计算价格的代码即可得到大大的优化:

/** 

 * @author mhcoding 

 */ 

public BigDecimal calPrice(BigDecimal orderPrice,User user) { 

 

     String vipType = user.getVipType(); 

     UserPayService strategy = UserPayServiceStrategyFactory.getByUserType(vipType); 

     return strategy.quote(orderPrice); 

以上代码中,不再需要 if-else 了,拿到用户的 vip 类型之后,直接通过工厂的 getByUserType 方法直接调用就可以了。

通过策略+工厂,我们的代码很大程度的优化了,大大提升了可读性和可维护性。

但是,上面还遗留了一个问题,那就是 UserPayServiceStrategyFactory 中用来保存所有的策略类的实例的 Map 是如何被初始化的?各个策略的实例对象如何塞进去的呢?

Spring Bean 的注册

还记得我们前面定义的 UserPayServiceStrategyFactory 中提供了的 Register 方法吗?他就是用来注册策略服务的。

接下来,我们就想办法调用 Register 方法,把 Spring 通过 IOC 创建出来的 Bean 注册进去就行了。

这种需求,可以借用 Spring 中提供的 InitializingBean 接口,这个接口为 Bean 提供了属性初始化后的处理方法。

它只包括 afterPropertiesSet 方法,凡是继承该接口的类,在 Bean 的属性初始化后都会执行该方法。

那么,我们将前面的各个策略类稍作改造即可:

/** 

 * @author mhcoding 

 */ 

@Service 

public class ParticularlyVipPayService implements UserPayService,InitializingBean { 

 

    @Override 

    public BigDecimal quote(BigDecimal orderPrice) { 

         if (消费金额大于30元) { 

            return 7折价格; 

        } 

    } 

 

    @Override 

    public void afterPropertiesSet() throws Exception { 

        UserPayServiceStrategyFactory.register("ParticularlyVip",this); 

    } 

 

@Service 

public class SuperVipPayService implements UserPayService ,InitializingBean{ 

 

    @Override 

    public BigDecimal quote(BigDecimal orderPrice) { 

        return 8折价格; 

    } 

 

    @Override 

    public void afterPropertiesSet() throws Exception { 

        UserPayServiceStrategyFactory.register("SuperVip",this); 

    } 

 

@Service   

public class VipPayService implements UserPayService,InitializingBean { 

 

    @Override 

    public BigDecimal quote(BigDecimal orderPrice) { 

        if(该用户超级会员刚过期并且尚未使用过临时折扣){ 

            临时折扣使用次数更新(); 

            returen 8折价格; 

        } 

        return 9折价格; 

    } 

 

    @Override 

    public void afterPropertiesSet() throws Exception { 

        UserPayServiceStrategyFactory.register("Vip",this); 

    } 

只需要每一个策略服务的实现类都实现 InitializingBean 接口,并实现其 afterPropertiesSet 方法,在这个方法中调用 UserPayServiceStrategyFactory.register 即可。

这样,在 Spring 初始化的时候,当创建 VipPayService、SuperVipPayService 和 ParticularlyVipPayService 的时候,会在 Bean 的属性初始化之后,把这个 Bean 注册到 UserPayServiceStrategyFactory 中。

以上代码,其实还是有一些重复代码的,这里面还可以引入模板方法模式进一步精简,这里就不展开了。

还有就是,UserPayServiceStrategyFactory.register 调用的时候,第一个参数需要传一个字符串,这里的话其实也可以优化掉。

比如使用枚举,或者在每个策略类中自定义一个 getUserType 方法,各自实现即可。

总结

本文,我们通过策略模式、工厂模式以及 Spring 的 InitializingBean,提升了代码的可读性以及可维护性,彻底消灭了一坨 if-else。

文中的这种做法,大家可以立刻尝试起来,这种实践,是我们日常开发中经常用到的,而且还有很多衍生的用法,也都非常好用。有机会后面再介绍。

其实,如果读者们对策略模式和工厂模式了解的话,文中使用的并不是严格意义上面的策略模式和工厂模式。

首先,策略模式中重要的 Context 角色在这里面是没有的,没有 Context,也就没有用到组合的方式,而是使用工厂代替了。

另外,这里面的 UserPayServiceStrategyFactory 其实只是维护了一个 Map,并提供了 Register 和 Get 方法而已,而工厂模式其实是帮忙创建对象的,这里并没有用到。

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读