java中用策略模式替代if-else的大段逻辑
java本来是一门以面向对象为主的语言,但很多人嘴上说着java面向对象,然后除了表映射实体之外,其他的还是面向过程的思路。
就比如今天要说的,代码中大段大段的if-else判断,每个if-else代码块中又有很多复杂的逻辑,导致整个代码混乱不堪,让别人看到就感觉看到屎一样的代码一样。
那么,如何优雅的替代这些代码呢,其实有个设计模式(策略模式)就很好的解决了这个问题。
比如说订单处理,订单会有多个type状态,比如说
type=1的时候,就执行普通订单的逻辑;
type=2的时候,就执行满减促销订单的逻辑;
type=3的时候,就执行满返促销订单的逻辑;
等等,可能type会有数十种甚至更多种情况。
然后有些人就会开始if-else了,比如有如下的伪代码:
if(type=1){
普通订单...(此处省略100多行处理逻辑)
}else if(type=2){
满减促销订单...(此处省略100多行处理逻辑)
}else if(type=3){
满返促销订单...(此处省略100多行处理逻辑)
}else if(type=n){
...(此处省略几百上千行的逻辑)
}
做的好点的,会把if-else代码块中的逻辑,抽成一个个的方法,会稍微显的代码清晰许多,但这些都是面向过程的思想。
我认为,这种情况就应该用以下这种方式,即,用策略模式代替if-else,真正做到面向对象。
把每种不同类型的订单抽成一个个对象,然后通过不同的注解标识来区分调用。
首先,本次例子用的是Spring-Boot框架,亲测没问题。SpringMVC框架应该也是没问题的。
定义一个订单类,里面有type属性,type可以是"1"、“2”、“3”…
定义一个抽象类AbstractHandler,里面有个抽象方法handle,入参是订单类
定义一个注解HandlerType,有个value属性,value是几就代表这个注解注的这个类是什么类型的订单
定义普通类HandlerImpl01,实现AbstractHandler,代表普通订单,即@HandlerType(“1”);
定义普通类HandlerImpl02,实现AbstractHandler,代表满减促销订单,即@HandlerType(“2”);
定义普通类HandlerImpl03,实现AbstractHandler,代表满返促销订单,即@HandlerType(“3”);
定义一个初始化类HandlerProcessor,实现BeanFactoryPostProcessor,过程如下:
1、找到带有注解@HandlerType的类,
2、以注解的值为key,对应的类为value,存在一个map中
3、将这个map作为构造函数的参数,初始化HandlerContext,将HandlerContext注册到spring中成为一个单例bean。
很明显,目的就是为了保存不同type对应的不同类。
定义类HandlerContext,有个map类型的属性叫handlerMap,有个getInstance的方法,入参是type,返回AbstractHandler。
最后使用的时候,是先调用handlerContext.getInstance方法,根据type获取对应的AbstractHandler。
然后再调用他的handle方法,执行对应订单类型的处理逻辑。
//@Data是lombok的注解,为了省略不写get/set方法
@Data
public class OrderDTO {
private String code;
private BigDecimal price;
/**
* 订单类型
* 1:普通订单
* 2:满减订单
* 3:满返订单
*/
private String type;
}
public abstract class AbstractHandler {
abstract public String handle(OrderDTO orderDTO);
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandlerType {
String value();
}
@Component
@HandlerType("1")
public class HandlerImpl01 extends AbstractHandler {
@Override
public String handle(OrderDTO orderDTO) {
System.out.println("处理type为1的订单,orderDTO.type="+orderDTO.getType());
return "success";
}
}
@Component
@HandlerType("2")
public class HandlerImpl02 extends AbstractHandler {
@Override
public String handle(OrderDTO orderDTO) {
System.out.println("处理type为2的订单,orderDTO.type="+orderDTO.getType());
return "success";
}
}
@Component
@HandlerType("3")
public class HandlerImpl03 extends AbstractHandler {
@Override
public String handle(OrderDTO orderDTO) {
System.out.println("处理type为3的订单,orderDTO.type="+orderDTO.getType());
return "success";
}
}
@Component
@SuppressWarnings("unchecked")
public class HandlerProcessor implements BeanFactoryPostProcessor {
//这里是具体的handler策略类的包的位置,为了后面的包扫描
private static final String HANDLER_PACKAGE = "com.zs.handler";
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<String, Class> handlerMap = new HashMap<>();
//包扫描
ClassScaner.scan(HANDLER_PACKAGE,HandlerType.class).forEach(clazz ->{
Annotation annotation = clazz.getAnnotation(HandlerType.class);
HandlerType handlerType = (HandlerType) annotation;
String type = handlerType.value();
System.out.println(type);
handlerMap.put(type,clazz);
});
HandlerContext handlerContext = new HandlerContext(handlerMap);
//注册单例
beanFactory.registerSingleton(HandlerContext.class.getName(),handlerContext);
}
}
public class HandlerContext {
private Map<String,Class> handlerMap;
public HandlerContext(Map<String, Class> handlerMap) {
this.handlerMap = handlerMap;
}
public AbstractHandler getInstance(String type){
Class clazz = handlerMap.get(type);
if(clazz == null){
throw new IllegalArgumentException("没有type对应的处理器,type:"+type);
}
return (AbstractHandler)SpringContextUtils.getBean(clazz);
}
}
定义接口:
public interface OrderService {
/**
* 根据订单类型处理订单
* @param orderDTO
* @return
*/
String handle(OrderDTO orderDTO);
}
实现接口:
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private HandlerContext handlerContext;
@Override
public String handle(OrderDTO orderDTO) {
System.out.println("OrderServiceImpl handle 方法开始执行===");
AbstractHandler handler = handlerContext.getInstance(orderDTO.getType());
return handler.handle(orderDTO);
}
}
包扫描的工具类:
public class ClassScaner implements ResourceLoaderAware {
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private final List<TypeFilter> includeFilters = new LinkedList<TypeFilter>();
private final List<TypeFilter> excludeFilters = new LinkedList<TypeFilter>();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
public ClassScaner() {
}
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory( resourceLoader);
}
// public final ResourceLoader getResourceLoader() {
// return this.resourcePatternResolver;
// }
public void addIncludeFilter(TypeFilter includeFilter) {
this.includeFilters.add(includeFilter);
}
// public void addExcludeFilter(TypeFilter excludeFilter) {
// this.excludeFilters.add(0, excludeFilter);
// }
// public void resetFilters(boolean useDefaultFilters) {
// this.includeFilters.clear();
// this.excludeFilters.clear();
// }
public static Set<Class> scan(String basePackage, Class<? extends Annotation>... annotations) {
ClassScaner cs = new ClassScaner();
for (Class anno : annotations)
cs.addIncludeFilter(new AnnotationTypeFilter(anno));
return cs.doScan(basePackage);
}
// public static Set scan(String[] basePackages, Class extends Annotation>... annotations) {
// ClassScaner cs = new ClassScaner();
// for (Class anno : annotations)
// cs.addIncludeFilter(new AnnotationTypeFilter(anno));
// Set classes = new HashSet();
// for (String s : basePackages)
// classes.addAll(cs.doScan(s));
// return classes;
// }
public Set<Class> doScan(String basePackage) {
Set<Class> classes = new HashSet<Class>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ org.springframework.util.ClassUtils
.convertClassNameToResourcePath(SystemPropertyUtils
.resolvePlaceholders(basePackage))
+ "/**/*.class";
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if ((includeFilters.size() == 0 && excludeFilters.size() == 0)
|| matches(metadataReader)) {
try {
classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
} catch (IOException ex) {
throw new BeanDefinitionStoreException(
"I/O failure during classpath scanning", ex);
}
return classes;
}
protected boolean matches(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return true;
}
}
return false;
}
}
spring工具类,为了获取bean
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String beanId) {
return (T) applicationContext.getBean(beanId);
}
public static <T> T getBean(Class<T> requiredType) {
return (T) applicationContext.getBean(requiredType);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
}