写代码的时候经常遇到这样的场景:根据某个字段值来进行不同的逻辑处理。例如,不同的会员等级在购物时有不同的折扣力度。如果会员的等级很多,那么代码中与之相关的if…elseif…else…会特别长,而且每新增一种等级时需要修改原先的代码。可以用策略模式来优化,消除这种场景下的if…elseif…else…,使代码看起来更优雅。

首先,定义一个接口

/** * 会员服务 */public interface VipService {    void handle();}

然后,定义实现类

/** * 白银会员 */public class SilverVipService implements VipService {    @Override    public void handle() {        System.out.println("白银");    }}/** * 黄金会员 */public class GoldVipService implements VipService {    @Override    public void handle() {        System.out.println("黄金");    }}

最后,定义一个工厂类,目的是当传入一个会员等级后,返回其对应的处理类

public class VipServiceFactory {    private static Map vipMap = new ConcurrentHashMap();    public static void register(String type, VipService service) {        vipMap.put(type, service);    }    public static VipService getService(String type) {        return vipMap.get(type);    }}

为了建立会员等级和与之对应的处理类之间的映射关系,这里通常可以有这么几种处理方式:

方式一:实现类手动注册

可以实现InitializingBean接口,或者在某个方法上加@PostConstruct注解

import org.springframework.beans.factory.InitializingBean;import org.springframework.stereotype.Component;/** * 白银会员 */@Componentpublic class SilverVipService implements VipService, InitializingBean {    @Override    public void handle() {        System.out.println("白银");    }    @Override    public void afterPropertiesSet() throws Exception {        VipServiceFactory.register("silver", this);    }}/** * 黄金会员 */@Componentpublic class GoldVipService implements VipService, InitializingBean {    @Override    public void handle() {        System.out.println("黄金");    }    @Override    public void afterPropertiesSet() throws Exception {        VipServiceFactory.register("gold", this);    }}

方式二:从Spring容器中直接获取Bean

public interface VipService {    void handle();    String getType();}/** * 白银会员 */@Componentpublic class SilverVipService implements VipService {    @Override    public void handle() {        System.out.println("白银");    }    @Override    public String getType() {        return "silver";    }}/** * 黄金会员 */@Componentpublic class GoldVipService implements VipService {    @Override    public void handle() {        System.out.println("黄金");    }    @Override    public String getType() {        return "gold";    }}/** * 上下文 */@Componentpublic class VipServiceFactory implements ApplicationContextAware {    private static Map vipMap = new ConcurrentHashMap();    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        Map map = applicationContext.getBeansOfType(VipService.class);        map.values().forEach(service -> vipMap.put(service.getType(), service));    }    public static VipService getService(String type) {        return vipMap.get(type);    }}/** * 测试 */@SpringBootTestclass DemoApplicationTests {    @Test    void contextLoads() {        VipServiceFactory.getService("silver").handle();    }}

方式三:反射+自定义注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface MemberLevel {    String value();}@MemberLevel("silver")@Componentpublic class SilverVipService implements VipService {    @Override    public void handle() {        System.out.println("白银");    }}@MemberLevel("gold")@Componentpublic class GoldVipService implements VipService {    @Override    public void handle() {        System.out.println("黄金");    }}/** * 上下文 */@Componentpublic class VipServiceFactory implements ApplicationContextAware {    private static Map vipMap = new ConcurrentHashMap();    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//        Map map = applicationContext.getBeansOfType(VipService.class);        Map map = applicationContext.getBeansWithAnnotation(MemberLevel.class);        for (Object bean : map.values()) {            if (bean instanceof VipService) {                String type = bean.getClass().getAnnotation(MemberLevel.class).value();                vipMap.put(type, (VipService) bean);            }        }    }    public static VipService getService(String type) {        return vipMap.get(type);    }}

完整示例代码

/** * 结算业务种类 * @Author: ChengJianSheng * @Date: 2023/1/16 */@Getterpublic enum SettlementBusiType {    RE1011("RE1011", "转贴现"),    RE4011("RE4011", "买断式贴现"),    RE4021("RE4021", "回购式贴现"),    RE4022("RE4022", "回购式贴现赎回");//    ......    private String code;    private String name;    SettlementBusiType(String code, String name) {        this.code = code;        this.name = name;    }}/** * 结算处理器 * @Author: ChengJianSheng * @Date: 2023/1/16 */public interface SettlementHandler {    /**     * 清算     */    void handle();    /**     * 获取业务种类     */    SettlementBusiType getBusiType();}/** * 转贴现结算处理 */@Componentpublic class RediscountSettlementHandler implements SettlementHandler {    @Override    public void handle() {        System.out.println("转贴现");    }    @Override    public SettlementBusiType getBusiType() {        return SettlementBusiType.RE1011;    }}/** * 买断式贴现结算处理 */@Componentpublic class BuyoutDiscountSettlementHandler implements SettlementHandler {    @Override    public void handle() {        System.out.println("买断式贴现");    }    @Override    public SettlementBusiType getBusiType() {        return SettlementBusiType.RE4011;    }}/** * 默认处理器 * @Author: ChengJianSheng * @Date: 2023/1/16 */@Componentpublic class DefaultSettlementHandler implements /*SettlementHandler,*/ ApplicationContextAware {    private static Map allHandlerMap = new ConcurrentHashMap();    public static SettlementHandler getHandler(SettlementBusiType busiType) {        return allHandlerMap.get(busiType);    }    @Override    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {        Map map = applicationContext.getBeansOfType(SettlementHandler.class);        map.values().forEach(e -> allHandlerMap.put(e.getBusiType(), e));    }}@SpringBootTestclass Demo2023ApplicationTests {    @Test    void contextLoads() {        // 收到结算结果通知,根据业务种类进行结算处理        SettlementHandler handler = DefaultSettlementHandler.getHandler(SettlementBusiType.RE1011);        if (null != handler) {            handler.handle();        }    }}