设计模式-工厂模式的实际应用-干掉if else

164 阅读2分钟

1.当一块庞大的逻辑需要用到很多if else,很可能一个判断括号中的代码就有跨越两个屏幕,那么它的阅读性和可维护性都会很低, 有什么办法改善呢?

例:有三种会员进行判断

public Double discount(BigDecimal orderPrice, String memberType) {

    if (memberType.equals("黄金会员")) {
        if (orderPrice.compareTo(new BigDecimal(100)) > -1) {
            //一百行代码 balala ...
            return 0.65;
        }
        return 0.7;
    }

    if (memberType.equals("白银会员")) {
        //一百行代码 balala ...
        return 0.8;
    }

    if (memberType.equals("黄铜会员")) {
        if (true) {
            //balabala
        }
        //一百行代码 balala ...
        return 0.9;
    }
    return 1.0;
}

使用策略模式来拆分三种会员的业务代码:

首先,创建一个接口,及它的三个会员的实现类,然后将各自业务拆分到实现类中

public interface UserPayService {

    public Double discount(BigDecimal orderPrice);

}

@Service
public class BrassVipPayServiceImpl implements UserPayService {
    @Override
    public Double discount(BigDecimal orderPrice) {
        //一百行代码 balala ...
        return 0.9;
    }
}

@Service
public class GoldVipPayServiceImpl implements UserPayService {
    @Override
    public Double discount(BigDecimal orderPrice) {
        if (orderPrice.compareTo(new BigDecimal(100)) > -1) {
            //一百行代码 balala ...
            return 0.65;
        }
        return 0.7;
    }
}

@Service
public class SilverVipPayServiceImpl implements UserPayService {
    @Override
    public Double discount(BigDecimal orderPrice) {
        //一百行代码 balala ...
        return 0.8;
    }
}

然后在使用的时候,发现好像并没有干掉if else, 因为你无法对service 进行自动装配

public Double discount2(BigDecimal orderPrice, String memberType) {
    if (memberType == "黄金会员") {
        UserPayService strategy = applicationContext.getBean(GoldVipPayServiceImpl.class);
        return strategy.discount(orderPrice);
    }

    if (memberType == "白银会员") {
        UserPayService strategy = applicationContext.getBean(BrassVipPayServiceImpl.class);
        return strategy.discount(orderPrice);
    }

    if (memberType == "黄铜会员") {
        UserPayService strategy = applicationContext.getBean(SilverVipPayServiceImpl.class);
        return strategy.discount(orderPrice);
    }
    return 1.0;
}

换一个思路,既然无法自动装配。那好像可以用一个Map将Servie存储起来,然后通过key获取

首先创建一个工厂类

@Component
public class UserPayServiceFactory {

    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){
        services.put(userType,userPayService);
    }
}

然后在Servie实现类中继承 InitializingBean 接口

@Service
public class BrassVipPayServiceImpl implements UserPayService, InitializingBean {
    @Override
    public Double discount(BigDecimal orderPrice) {
        //一百行代码 balala ...
        return 0.9;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        UserPayServiceFactory.register("黄铜会员",this);
    }
}

@Service
public class SilverVipPayServiceImpl implements UserPayService, InitializingBean {

    @Override
    public Double discount(BigDecimal orderPrice) {
        //一百行代码 balala ...
        return 0.8;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        UserPayServiceFactory.register("白银会员",this);
    }
}
............

实现InitializingBean 接口 会有一个afterPropertiesSet()方法。Spring 在初始化Bean的时候会调用它,也就是说,Spring 在初始化这个实现类的时候,也就将它放入了工厂类的Map中。然后我们调用起来就比较方便了。

@Test
void contextLoads() {
    UserPayService strategy = UserPayServiceFactory.getByUserType("黄金会员");
    System.out.println(strategy.discount(new BigDecimal(300)));
}

完工