写代码的时候经常遇到这样的场景:根据某个字段值来进行不同的逻辑处理。例如,不同的会员等级在购物时有不同的折扣力度。如果会员的等级很多,那么代码中与之相关的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<String, VipService> 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;
/**
* 白银会员
*/
@Component
public class SilverVipService implements VipService, InitializingBean {
@Override
public void handle() {
System.out.println("白银");
}
@Override
public void afterPropertiesSet() throws Exception {
VipServiceFactory.register("silver", this);
}
}
/**
* 黄金会员
*/
@Component
public 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();
}
/**
* 白银会员
*/
@Component
public class SilverVipService implements VipService {
@Override
public void handle() {
System.out.println("白银");
}
@Override
public String getType() {
return "silver";
}
}
/**
* 黄金会员
*/
@Component
public class GoldVipService implements VipService {
@Override
public void handle() {
System.out.println("黄金");
}
@Override
public String getType() {
return "gold";
}
}
/**
* 上下文
*/
@Component
public class VipServiceFactory implements ApplicationContextAware {
private static Map<String, VipService> vipMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, VipService> map = applicationContext.getBeansOfType(VipService.class);
map.values().forEach(service -> vipMap.put(service.getType(), service));
}
public static VipService getService(String type) {
return vipMap.get(type);
}
}
/**
* 测试
*/
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
VipServiceFactory.getService("silver").handle();
}
}
方式三:反射+自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MemberLevel {
String value();
}
@MemberLevel("silver")
@Component
public class SilverVipService implements VipService {
@Override
public void handle() {
System.out.println("白银");
}
}
@MemberLevel("gold")
@Component
public class GoldVipService implements VipService {
@Override
public void handle() {
System.out.println("黄金");
}
}
/**
* 上下文
*/
@Component
public class VipServiceFactory implements ApplicationContextAware {
private static Map<String, VipService> vipMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// Map<String, VipService> map = applicationContext.getBeansOfType(VipService.class);
Map<String, Object> 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
*/
@Getter
public 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();
}
/**
* 转贴现结算处理
*/
@Component
public class RediscountSettlementHandler implements SettlementHandler {
@Override
public void handle() {
System.out.println("转贴现");
}
@Override
public SettlementBusiType getBusiType() {
return SettlementBusiType.RE1011;
}
}
/**
* 买断式贴现结算处理
*/
@Component
public class BuyoutDiscountSettlementHandler implements SettlementHandler {
@Override
public void handle() {
System.out.println("买断式贴现");
}
@Override
public SettlementBusiType getBusiType() {
return SettlementBusiType.RE4011;
}
}
/**
* 默认处理器
* @Author: ChengJianSheng
* @Date: 2023/1/16
*/
@Component
public class DefaultSettlementHandler implements /*SettlementHandler,*/ ApplicationContextAware {
private static Map<SettlementBusiType, SettlementHandler> allHandlerMap = new ConcurrentHashMap<>();
public static SettlementHandler getHandler(SettlementBusiType busiType) {
return allHandlerMap.get(busiType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, SettlementHandler> map = applicationContext.getBeansOfType(SettlementHandler.class);
map.values().forEach(e -> allHandlerMap.put(e.getBusiType(), e));
}
}
@SpringBootTest
class Demo2023ApplicationTests {
@Test
void contextLoads() {
SettlementHandler handler = DefaultSettlementHandler.getHandler(SettlementBusiType.RE1011);
if (null != handler) {
handler.handle();
}
}
}