[设计模式] ------ 策略模式实战:java中替代if-else的大段逻辑
java中用策略模式替代if-else的大段邏輯
問題:
java本來是一門以面向?qū)ο鬄橹鞯恼Z言,但很多人嘴上說著java面向?qū)ο?#xff0c;然后除了表映射實(shí)體之外,其他的還是面向過程的思路。
就比如今天要說的,代碼中大段大段的if-else判斷,每個(gè)if-else代碼塊中又有很多復(fù)雜的邏輯,導(dǎo)致整個(gè)代碼混亂不堪,讓別人看到就感覺看到屎一樣的代碼一樣。
那么,如何優(yōu)雅的替代這些代碼呢,其實(shí)有個(gè)設(shè)計(jì)模式(策略模式)就很好的解決了這個(gè)問題。
情景舉例:
比如說訂單處理,訂單會(huì)有多個(gè)type狀態(tài),比如說
type=1的時(shí)候,就執(zhí)行普通訂單的邏輯;
type=2的時(shí)候,就執(zhí)行滿減促銷訂單的邏輯;
type=3的時(shí)候,就執(zhí)行滿返促銷訂單的邏輯;
等等,可能type會(huì)有數(shù)十種甚至更多種情況。
然后有些人就會(huì)開始if-else了,比如有如下的偽代碼:
if(type=1){普通訂單...(此處省略100多行處理邏輯) }else if(type=2){滿減促銷訂單...(此處省略100多行處理邏輯) }else if(type=3){滿返促銷訂單...(此處省略100多行處理邏輯) }else if(type=n){...(此處省略幾百上千行的邏輯) }做的好點(diǎn)的,會(huì)把if-else代碼塊中的邏輯,抽成一個(gè)個(gè)的方法,會(huì)稍微顯的代碼清晰許多,但這些都是面向過程的思想。
我認(rèn)為,這種情況就應(yīng)該用以下這種方式,即,用策略模式代替if-else,真正做到面向?qū)ο蟆?br /> 把每種不同類型的訂單抽成一個(gè)個(gè)對(duì)象,然后通過不同的注解標(biāo)識(shí)來區(qū)分調(diào)用。
用策略模式代替if-else:
首先,本次例子用的是Spring-Boot框架,親測(cè)沒問題。SpringMVC框架應(yīng)該也是沒問題的。
定義一個(gè)訂單類,里面有type屬性,type可以是"1"、“2”、“3”…
定義一個(gè)抽象類AbstractHandler,里面有個(gè)抽象方法handle,入?yún)⑹怯唵晤?br /> 定義一個(gè)注解HandlerType,有個(gè)value屬性,value是幾就代表這個(gè)注解注的這個(gè)類是什么類型的訂單
定義普通類HandlerImpl01,實(shí)現(xiàn)AbstractHandler,代表普通訂單,即@HandlerType(“1”);
定義普通類HandlerImpl02,實(shí)現(xiàn)AbstractHandler,代表滿減促銷訂單,即@HandlerType(“2”);
定義普通類HandlerImpl03,實(shí)現(xiàn)AbstractHandler,代表滿返促銷訂單,即@HandlerType(“3”);
定義一個(gè)初始化類HandlerProcessor,實(shí)現(xiàn)BeanFactoryPostProcessor,過程如下:
1、找到帶有注解@HandlerType的類,
2、以注解的值為key,對(duì)應(yīng)的類為value,存在一個(gè)map中
3、將這個(gè)map作為構(gòu)造函數(shù)的參數(shù),初始化HandlerContext,將HandlerContext注冊(cè)到spring中成為一個(gè)單例bean。
很明顯,目的就是為了保存不同type對(duì)應(yīng)的不同類。
定義類HandlerContext,有個(gè)map類型的屬性叫handlerMap,有個(gè)getInstance的方法,入?yún)⑹莟ype,返回AbstractHandler。
最后使用的時(shí)候,是先調(diào)用handlerContext.getInstance方法,根據(jù)type獲取對(duì)應(yīng)的AbstractHandler。
然后再調(diào)用他的handle方法,執(zhí)行對(duì)應(yīng)訂單類型的處理邏輯。
具體代碼如下:
//@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 {@Overridepublic String handle(OrderDTO orderDTO) {System.out.println("處理type為1的訂單,orderDTO.type="+orderDTO.getType());return "success";} } @Component @HandlerType("2") public class HandlerImpl02 extends AbstractHandler {@Overridepublic String handle(OrderDTO orderDTO) {System.out.println("處理type為2的訂單,orderDTO.type="+orderDTO.getType());return "success";} } @Component @HandlerType("3") public class HandlerImpl03 extends AbstractHandler {@Overridepublic 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";@Overridepublic 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);//注冊(cè)單例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對(duì)應(yīng)的處理器,type:"+type);}return (AbstractHandler)SpringContextUtils.getBean(clazz);} }定義接口:
public interface OrderService {/*** 根據(jù)訂單類型處理訂單* @param orderDTO* @return*/String handle(OrderDTO orderDTO); }實(shí)現(xiàn)接口:
@Service public class OrderServiceImpl implements OrderService {@Resourceprivate HandlerContext handlerContext;@Overridepublic String handle(OrderDTO orderDTO) {System.out.println("OrderServiceImpl handle 方法開始執(zhí)行===");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<Class> scan(String[] basePackages, Class<? extends Annotation>... annotations) { // ClassScaner cs = new ClassScaner(); // for (Class anno : annotations) // cs.addIncludeFilter(new AnnotationTypeFilter(anno)); // Set<Class> classes = new HashSet<Class>(); // 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);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtils.applicationContext = applicationContext;} }總結(jié)
以上是生活随笔為你收集整理的[设计模式] ------ 策略模式实战:java中替代if-else的大段逻辑的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息队列(5):RocketMQ
- 下一篇: hash和一致性hash