本篇內(nèi)容主要講解“if-else嵌套的用法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“if-else嵌套的用法”吧!
創(chuàng)新互聯(lián)建站是專業(yè)的黎平網(wǎng)站建設(shè)公司,黎平接單;提供成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行黎平網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!
先說一下具體的需求:公司推廣入口很多,每一個下單來源在下單時都做特殊的邏輯處理,可能每兩天就會加一個來源。
那么按照傳統(tǒng)的實現(xiàn)方式代碼就是如下:
public class OrderServiceImpl implements IOrderService { @Override public String handle(OrderDTO dto) { String type = dto.getType(); if ("1".equals(type)) { return "處理普通訂單"; } else if ("2".equals(type)) { return "處理團購訂單"; } else if ("3".equals(type)) { return "處理促銷訂單"; } return null; } }
為什么非得寫的這么臃腫?很多同事會說:“哎呀,沒辦法呀,業(yè)務(wù)催的緊,這樣開發(fā)效率快省事”。的確是句大實話,很多時候業(yè)務(wù)方確實像催命鬼一樣的讓你趕工期,想快速實現(xiàn)功能,這樣寫是最好的選擇。
上邊的代碼看似還算清晰,可如果我告訴你公司訂單來源有上百種,你想象一下那種臃腫的if-else,去翻代碼時是什么感受?
策略模式是oop
中最著名的設(shè)計模式之一,是對方法行為的抽象,可以歸類為行為設(shè)計模式,也是oop
中interface
經(jīng)典的應(yīng)用。其特點簡單又實用,是我最喜歡的模式之一。
策略模式定義了一個擁有共同行為的算法族,每個算法都被封裝起來,可以互相替換,獨立于客戶端而變化。
不少人說:Java的設(shè)計模式背了很多,可日常還不就是寫if-else的業(yè)務(wù),根本就不用到。其實不是用不到是沒有用到合適的位置!
針對同一問題的多種處理方式,僅僅是具體行為有差別時;
需要安全地封裝多種同一類型的操作時;
同一抽象類有多個子類,而客戶端需要使用if-else 或者 switch-case 來選擇具體子類時。
這個是用策略模式修改后代碼:
@Component @OrderHandlerType(16) public class DispatchModeProcessor extends AbstractHandler{ @Autowired private OrderStencilledService orderStencilledService; @Override public void handle(OrderBO orderBO) { /** * 訂單完結(jié)廣播通知(1 - 支付完成) */ orderStencilledService.dispatchModeFanout(orderBO); /** * SCMS 出庫單 */ orderStencilledService.createScmsDeliveryOrder(orderBO.getPayOrderInfoBO().getLocalOrderNo()); } }
每個訂單來源都有自己單獨的邏輯實現(xiàn)類,而每次需要添加訂單來源,直接新建實現(xiàn)類,修改@OrderHandlerType(16)
的數(shù)值即可,再也不用去翻那幾百行的if-lese,一勞永逸!
1、定義一個標識訂單來源的注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface OrderHandlerType { int value() default 0; }
2、抽象出來一個具體的業(yè)務(wù)處理器
public abstract class AbstractHandler { abstract public void handle(OrderBO orderBO); }
3、項目啟動掃描 handler
入口
@Component @SuppressWarnings({"unused","rawtypes"}) public class HandlerProcessor implements BeanFactoryPostProcessor { private String basePackage = "com.ecej.order.pipeline.processor"; public static final Logger log = LoggerFactory.getLogger(HandlerProcessor.class); @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { Map<Integer,Class> map = new HashMap<Integer,Class>(); ClassScaner.scan(basePackage, OrderHandlerType.class).forEach(x ->{ int type = x.getAnnotation(OrderHandlerType.class).value(); map.put(type,x); }); beanFactory.registerSingleton(OrderHandlerType.class.getName(), map); log.info("處理器初始化{}", JSONObject.toJSONString(beanFactory.getBean(OrderHandlerType.class.getName()))); } }
4、掃描需要用到的工具類
public class ClassScaner { private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); private final List<TypeFilter> includeFilters = new ArrayList<TypeFilter>(); private final List<TypeFilter> excludeFilters = new ArrayList<TypeFilter>(); private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver); /** * 添加包含的Fiter * @param includeFilter */ public void addIncludeFilter(TypeFilter includeFilter) { this.includeFilters.add(includeFilter); } /** * 添加排除的Fiter * @param includeFilter */ public void addExcludeFilter(TypeFilter excludeFilter) { this.excludeFilters.add(excludeFilter); } /** * 掃描指定的包,獲取包下所有的Class * @param basePackage 包名 * @param targetTypes 需要指定的目標類型,可以是pojo,可以是注解 * @return Set<Class<?>> */ public static Set<Class<?>> scan(String basePackage, Class<?>... targetTypes) { ClassScaner cs = new ClassScaner(); for (Class<?> targetType : targetTypes){ if(TypeUtils.isAssignable(Annotation.class, targetType)){ cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType)); }else{ cs.addIncludeFilter(new AssignableTypeFilter(targetType)); } } return cs.doScan(basePackage); } /** * 掃描指定的包,獲取包下所有的Class * @param basePackages 包名,多個 * @param targetTypes 需要指定的目標類型,可以是pojo,可以是注解 * @return Set<Class<?>> */ public static Set<Class<?>> scan(String[] basePackages, Class<?>... targetTypes) { ClassScaner cs = new ClassScaner(); for (Class<?> targetType : targetTypes){ if(TypeUtils.isAssignable(Annotation.class, targetType)){ cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType)); }else{ cs.addIncludeFilter(new AssignableTypeFilter(targetType)); } } Set<Class<?>> classes = new HashSet<Class<?>>(); for (String s : basePackages){ classes.addAll(cs.doScan(s)); } return classes; } /** * 掃描指定的包,獲取包下所有的Class * @param basePackages 包名 * @return Set<Class<?>> */ public Set<Class<?>> doScan(String [] basePackages) { Set<Class<?>> classes = new HashSet<Class<?>>(); for (String basePackage :basePackages) { classes.addAll(doScan(basePackage)); } return classes; } /** * 掃描指定的包,獲取包下所有的Class * @param basePackages 包名 * @return Set<Class<?>> */ public Set<Class<?>> doScan(String basePackage) { Set<Class<?>> classes = new HashSet<Class<?>>(); try { String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + 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 ignore) {} } } } } catch (IOException ex) { throw new RuntimeException("I/O failure during classpath scanning", ex); } return classes; } /** * 處理 excludeFilters和includeFilters * @param metadataReader * @return boolean * @throws IOException */ private 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; } }
5、 根據(jù)類型實例化抽象類
@Component public class HandlerContext { @Autowired private ApplicationContext beanFactory; public AbstractHandler getInstance(Integer type){ Map<Integer,Class> map = (Map<Integer, Class>) beanFactory.getBean(OrderHandlerType.class.getName()); return (AbstractHandler)beanFactory.getBean(map.get(type)); } }
6、調(diào)用入口,我這里是接的MQ消息,會批量的處理多個訂單來源
@Component @RabbitListener(queues = "OrderPipelineQueue") public class PipelineSubscribe{ private final Logger LOGGER = LoggerFactory.getLogger(PipelineSubscribe.class); @Autowired private HandlerContext HandlerContext; @Autowired private OrderValidateService orderValidateService; @RabbitHandler public void subscribeMessage(MessageBean bean){ OrderBO orderBO = JSONObject.parseObject(bean.getOrderBO(), OrderBO.class); if(null != orderBO &&CollectionUtils.isNotEmpty(bean.getType())) { for(int value:bean.getType()) { AbstractHandler handler = HandlerContext.getInstance(value); handler.handle(orderBO); } } } }
接收實體 MessageBean
類代碼
public class MessageBean implements Serializable { private static final long serialVersionUID = 5454831432308782668L; private String cachKey; private List<Integer> type; private String orderBO; public MessageBean(List<Integer> type, String orderBO) { this.type = type; this.orderBO = orderBO; } }
易于擴展,增加一個新的策略只需要添加一個具體的策略類即可,基本不需要改變原有的代碼,符合開放封閉原則
避免使用多重條件選擇語句,充分體現(xiàn)面向?qū)ο笤O(shè)計思想 策略類之間可以自由切換,由于策略類都實現(xiàn)同一個接口,所以使它們之間可以自由切換
每個策略類使用一個策略類,符合單一職責原則 客戶端與策略算法解耦,兩者都依賴于抽象策略接口,符合依賴反轉(zhuǎn)原則
客戶端不需要知道都有哪些策略類,符合最小知識原則
策略模式,當策略算法太多時,會造成很多的策略類
客戶端不知道有哪些策略類,不能決定使用哪個策略類,這點可以通過封裝common公共包解決,也可以考慮使IOC容器
和依賴注入
的方式來解決。
以下是訂單來源策略類的一部分,不得不說策略類確實比較多。
凡事都有他的兩面性,if-else
多層嵌套和也都有其各自的優(yōu)缺點:
if-else
的有點就是簡單,想快速迭代功能,邏輯嵌套少且不會持續(xù)增加,if-else
更好些,缺點也是顯而易見,代碼臃腫繁瑣不便于維護。
策略模式
將各個場景的邏輯剝離出來維護,同一抽象類有多個子類,需要使用if-else
或者 switch-case
來選擇具體子類時,建議選策略模式,他的缺點就是會產(chǎn)生比較多的策略類文件。
兩種實現(xiàn)方式各有利弊,如何選擇還是要依據(jù)具體業(yè)務(wù)場景,還是那句話設(shè)計模式不是為了用而用,一定要用在最合適的位置。
到此,相信大家對“if-else嵌套的用法”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
當前題目:if-else嵌套的用法
當前路徑:http://jinyejixie.com/article0/ggsgoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營銷、全網(wǎng)營銷推廣、品牌網(wǎng)站制作、網(wǎng)站導(dǎo)航、定制開發(fā)、Google
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)