真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如惡化清除滿屏的if-else

本篇內(nèi)容介紹了“如惡化清除滿屏的if-else”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比綏江網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式綏江網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋綏江地區(qū)。費用合理售后完善,10年實體公司更值得信賴。

又臭又長的 if...else

廢話不多說,先看看下面的代碼:

public interface IPay {       void pay();   }    @Service   public class AliaPay implements IPay {        @Override        public void pay() {           System.out.println("===發(fā)起支付寶支付===");        }   }    @Service   public class WeixinPay implements IPay {        @Override        public void pay() {            System.out.println("===發(fā)起微信支付===");        }   }    @Service   public class JingDongPay implements IPay {        @Override        public void pay() {           System.out.println("===發(fā)起京東支付===");        }   }    @Service   public class PayService {        @Autowired        private AliaPay aliaPay;        @Autowired        private WeixinPay weixinPay;        @Autowired        private JingDongPay jingDongPay;          public void toPay(String code) {            if ("alia".equals(code)) {                aliaPay.pay();            } else if ("weixin".equals(code)) {                 weixinPay.pay();            } else if ("jingdong".equals(code)) {                 jingDongPay.pay();            } else {                 System.out.println("找不到支付方式");            }        }   }

PayService 類的 toPay 方法主要是為了發(fā)起支付,根據(jù)不同的 code,決定調(diào)用用不同的支付類(比如:aliaPay)的 pay  方法進行支付。

這段代碼有什么問題呢?也許有些人就是這么干的。

試想一下,如果支付方式越來越多,比如:又加了百度支付、美團支付、銀聯(lián)支付等等,就需要改 toPay 方法的代碼,增加新的 else...if  判斷,判斷多了就會導(dǎo)致邏輯越來越多?

很明顯,這里違反了設(shè)計模式六大原則的:

  • 開閉原則:對擴展開放,對修改關(guān)閉。就是說增加新功能要盡量少改動已有代碼。

  • 單一職責(zé)原則:顧名思義,要求邏輯盡量單一,不要太復(fù)雜,便于復(fù)用。

那有什么辦法可以解決這個問題呢?

消除 if...else 的錦囊妙計

使用注解

代碼中之所以要用 code 判斷使用哪個支付類,是因為 code 和支付類沒有一個綁定關(guān)系,如果綁定關(guān)系存在了,就可以不用判斷了。

我們先定義一個注解:

@Retention(RetentionPolicy.RUNTIME)   @Target(ElementType.TYPE)   public @interface PayCode {         String value();          String name();   }

在所有的支付類上都加上該注解:

@PayCode(value = "alia", name = "支付寶支付")   @Service   public class AliaPay implements IPay {         @Override        public void pay() {            System.out.println("===發(fā)起支付寶支付===");        }   }     @PayCode(value = "weixin", name = "微信支付")   @Service   public class WeixinPay implements IPay {         @Override        public void pay() {            System.out.println("===發(fā)起微信支付===");        }   }    @PayCode(value = "jingdong", name = "京東支付")   @Service   public class JingDongPay implements IPay {         @Override        public void pay() {           System.out.println("===發(fā)起京東支付===");        }   }

然后增加最關(guān)鍵的類:

@Service   public class PayService2 implements ApplicationListener {         private static Map payMap = null;         @Override        public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {            ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();            Map beansWithAnnotation = applicationContext.getBeansWithAnnotation(PayCode.class);             if (beansWithAnnotation != null) {                payMap = new HashMap<>();                beansWithAnnotation.forEach((key, value) ->{                    String bizType = value.getClass().getAnnotation(PayCode.class).value();                    payMap.put(bizType, (IPay) value);                });            }        }         public void pay(String code) {           payMap.get(code).pay();        }   }

PayService2 類實現(xiàn)了 ApplicationListener 接口,這樣在 onApplicationEvent 方法中,就可以拿到  ApplicationContext 的實例。

我們再獲取打了 PayCode 注解的類,放到一個 map 中,map 中的 key 就是 PayCode 注解中定義的 value,跟 code  參數(shù)一致,value 是支付類的實例。

這樣,每次就可以每次直接通過 code 獲取支付類實例,而不用 if...else 判斷了。

如果要加新的支付方法,只需在支付類上面打上 PayCode 注解定義一個新的 code 即可。

注意:這種方式的 code 可以沒有業(yè)務(wù)含義,可以是純數(shù)字,只有不重復(fù)就行。

動態(tài)拼接名稱

該方法主要針對 code 是有業(yè)務(wù)含義的場景。

@Service   public class PayService3 implements ApplicationContextAware {         private ApplicationContext applicationContext;        private static final String SUFFIX = "Pay";         @Override        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {           this.applicationContext = applicationContext;        }         public void toPay(String payCode) {            ((IPay) applicationContext.getBean(getBeanName(payCode))).pay();        }         public String getBeanName(String payCode) {            return payCode + SUFFIX;        }   }

我們可以看到,支付類 bean 的名稱是由 code 和后綴拼接而成,比如:aliaPay、weixinPay 和 jingDongPay。

這就要求支付類取名的時候要特別注意,前面的一段要和 code 保持一致。

調(diào)用的支付類的實例是直接從 ApplicationContext 實例中獲取的,默認(rèn)情況下 bean 是單例的,放在內(nèi)存的一個 map  中,所以不會有性能問題。

特別說明一下,這種方法實現(xiàn)了 ApplicationContextAware 接口跟上面的 ApplicationListener  接口不一樣,是想告訴大家獲取 ApplicationContext 實例的方法不只一種。

模板方法判斷

當(dāng)然除了上面介紹的兩種方法之外,Spring 的源碼實現(xiàn)中也告訴我們另外一種思路,解決 if...else 問題。

我們先一起看看 Spring AOP 的部分源碼,看一下 DefaultAdvisorAdapterRegistry 的 wrap 方法:

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {        if (adviceObject instanceof Advisor) {           return (Advisor) adviceObject;        }        if (!(adviceObject instanceof Advice)) {           throw new UnknownAdviceTypeException(adviceObject);        }        Advice advice = (Advice) adviceObject;        if (advice instanceof MethodInterceptor) {             return new DefaultPointcutAdvisor(advice);        }        for (AdvisorAdapter adapter : this.adapters) {            if (adapter.supportsAdvice(advice)) {                return new DefaultPointcutAdvisor(advice);            }        }        throw new UnknownAdviceTypeException(advice);    }

重點看看 supportAdvice 方法,有三個類實現(xiàn)了這個方法。

我們隨便抽一個類看看:

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {         @Override        public boolean supportsAdvice(Advice advice) {           return (advice instanceof AfterReturningAdvice);        }         @Override        public MethodInterceptor getInterceptor(Advisor advisor) {           AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();           return new AfterReturningAdviceInterceptor(advice);        }    }

該類的 supportsAdvice 方法非常簡單,只是判斷了一下 advice 的類型是不是 AfterReturningAdvice。

我們看到這里應(yīng)該有所啟發(fā)。

其實,我們可以這樣做,定義一個接口或者抽象類,里面有個 support 方法判斷參數(shù)傳的 code 是否自己可以處理,如果可以處理則走支付邏輯。

public interface IPay {        boolean support(String code);         void pay();   }    @Service   public class AliaPay implements IPay {         @Override        public boolean support(String code) {           return "alia".equals(code);        }         @Override        public void pay() {           System.out.println("===發(fā)起支付寶支付===");        }   }    @Service   public class WeixinPay implements IPay {         @Override        public boolean support(String code) {           return "weixin".equals(code);        }         @Override        public void pay() {           System.out.println("===發(fā)起微信支付===");        }   }    @Service   public class JingDongPay implements IPay {        @Override        public boolean support(String code) {           return "jingdong".equals(code);        }         @Override        public void pay() {           System.out.println("===發(fā)起京東支付===");        }   }

每個支付類都有一個 support 方法,判斷傳過來的 code 是否和自己定義的相等。

@Service   public class PayService4 implements ApplicationContextAware, InitializingBean {         private ApplicationContext applicationContext;        private List payList = null;         @Override        public void afterPropertiesSet() throws Exception {            if (payList == null) {                payList = new ArrayList<>();                Map beansOfType = applicationContext.getBeansOfType(IPay.class);                 beansOfType.forEach((key, value) -> payList.add(value));            }        }         @Override        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {           this.applicationContext = applicationContext;        }         public void toPay(String code) {            for (IPay iPay : payList) {                if (iPay.support(code)) {                   iPay.pay();                }            }        }   }

這段代碼中先把實現(xiàn)了 IPay 接口的支付類實例初始化到一個 list 集合中,返回在調(diào)用支付接口時循環(huán)遍歷這個 list 集合,如果 code  跟自己定義的一樣,則調(diào)用當(dāng)前的支付類實例的 pay 方法。

策略+工廠模式

這種方式也是用于 code 是有業(yè)務(wù)含義的場景:

  • 策略模式定義了一組算法,把它們一個個封裝起來, 并且使它們可相互替換。

  • 工廠模式用于封裝和管理對象的創(chuàng)建,是一種創(chuàng)建型模式。

public interface IPay {     void pay(); }  @Service public class AliaPay implements IPay {      @PostConstruct     public void init() {         PayStrategyFactory.register("aliaPay", this);     }       @Override     public void pay() {         System.out.println("===發(fā)起支付寶支付===");     }  }  @Service public class WeixinPay implements IPay {      @PostConstruct     public void init() {         PayStrategyFactory.register("weixinPay", this);     }      @Override     public void pay() {         System.out.println("===發(fā)起微信支付===");     } }  @Service public class JingDongPay implements IPay {      @PostConstruct     public void init() {         PayStrategyFactory.register("jingDongPay", this);     }      @Override     public void pay() {         System.out.println("===發(fā)起京東支付===");     } }  public class PayStrategyFactory {      private static Map PAY_REGISTERS = new HashMap<>();       public static void register(String code, IPay iPay) {         if (null != code && !"".equals(code)) {             PAY_REGISTERS.put(code, iPay);         }     }       public static IPay get(String code) {         return PAY_REGISTERS.get(code);     } }  @Service public class PayService3 {      public void toPay(String code) {         PayStrategyFactory.get(code).pay();     } }

這段代碼的關(guān)鍵是 PayStrategyFactory 類,它是一個策略工廠,里面定義了一個全局的 map,在所有 IPay 的實現(xiàn)類中注冊當(dāng)前實例到  map 中。

然后在調(diào)用的地方通過 PayStrategyFactory 類根據(jù) code 從 map 獲取支付類實例即可。

責(zé)任鏈模式

這種方式在代碼重構(gòu)時用來消除 if...else 非常有效。

責(zé)任鏈模式:將請求的處理對象像一條長鏈一般組合起來,形成一條對象鏈。請求并不知道具體執(zhí)行請求的對象是哪一個,這樣就實現(xiàn)了請求與處理對象之間的解耦。

常用的 filter、spring aop 就是使用了責(zé)任鏈模式,這里我稍微改良了一下,具體代碼如下:

public abstract class PayHandler {      @Getter     @Setter     protected PayHandler next;      public abstract void pay(String pay);  }  @Service public class AliaPayHandler extends PayHandler {       @Override     public void pay(String code) {         if ("alia".equals(code)) {             System.out.println("===發(fā)起支付寶支付===");         } else {             getNext().pay(code);         }     }  }  @Service public class WeixinPayHandler extends PayHandler {      @Override     public void pay(String code) {         if ("weixin".equals(code)) {             System.out.println("===發(fā)起微信支付===");         } else {             getNext().pay(code);         }     } }  @Service public class JingDongPayHandler extends PayHandler {       @Override     public void pay(String code) {         if ("jingdong".equals(code)) {             System.out.println("===發(fā)起京東支付===");         } else {             getNext().pay(code);         }     } }  @Service public class PayHandlerChain implements ApplicationContextAware, InitializingBean {      private ApplicationContext applicationContext;     private PayHandler header;       public void handlePay(String code) {         header.pay(code);     }      @Override     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {         this.applicationContext = applicationContext;     }      @Override     public void afterPropertiesSet() throws Exception {         Map beansOfTypeMap = applicationContext.getBeansOfType(PayHandler.class);         if (beansOfTypeMap == null || beansOfTypeMap.size() == 0) {             return;         }         List handlers = beansOfTypeMap.values().stream().collect(Collectors.toList());         for (int i = 0; i < handlers.size(); i++) {             PayHandler payHandler = handlers.get(i);             if (i != handlers.size() - 1) {                 payHandler.setNext(handlers.get(i + 1));             }         }         header = handlers.get(0);     } }

這段代碼的關(guān)鍵是每個 PayHandler 的子類,都定義了下一個需要執(zhí)行的 PayHandler 子類,構(gòu)成一個鏈?zhǔn)秸{(diào)用,通過  PayHandlerChain 把這種鏈?zhǔn)浇Y(jié)構(gòu)組裝起來。

其他的消除 if...else 的方法

當(dāng)然實際項目開發(fā)中使用 if...else 判斷的場景非常多,上面只是其中幾種場景。下面再列舉一下,其他常見的場景。

①根據(jù)不同的數(shù)字返回不同的字符串

代碼如下:

public String getMessage(int code) {        if (code == 1) {           return "成功";        } else if (code == -1) {           return "失敗";        } else if (code == -2) {           return "網(wǎng)絡(luò)超時";        } else if (code == -3) {           return "參數(shù)錯誤";        }        throw new RuntimeException("code錯誤");   }

其實,這種判斷沒有必要,用一個枚舉就可以搞定。

public enum MessageEnum {        SUCCESS(1, "成功"),        FAIL(-1, "失敗"),        TIME_OUT(-2, "網(wǎng)絡(luò)超時"),        PARAM_ERROR(-3, "參數(shù)錯誤");         private int code;        private String message;         MessageEnum(int code, String message) {            this.code = code;            this.message = message;        }         public int getCode() {           return this.code;        }         public String getMessage() {           return this.message;        }         public static MessageEnum getMessageEnum(int code) {           return Arrays.stream(MessageEnum.values()).filter(x -> x.code == code).findFirst().orElse(null);        }   }

再把調(diào)用方法稍微調(diào)整一下:

public String getMessage(int code) {        MessageEnum messageEnum = MessageEnum.getMessageEnum(code);        return messageEnum.getMessage();   }

完美。

②集合中的判斷

上面的枚舉 MessageEnum 中的 getMessageEnum 方法,如果不用 java8 的語法的話,可能要這樣寫:

public static MessageEnum getMessageEnum(int code) {        for (MessageEnum messageEnum : MessageEnum.values()) {            if (code == messageEnum.code) {               return messageEnum;            }        }        return null;   }

對于集合中過濾數(shù)據(jù),或者查找方法,java8 有更簡單的方法消除 if...else 判斷。

public static MessageEnum getMessageEnum(int code) {        return Arrays.stream(MessageEnum.values()).filter(x -> x.code == code).findFirst().orElse(null);   }

③簡單的判斷

其實有些簡單的 if...else 完全沒有必要寫,可以用三目運算符代替,比如這種情況:

public String getMessage2(int code) {        if(code == 1) {           return  "成功";        }        return "失敗";   }

改成三目運算符:

public String getMessage2(int code) {       return code == 1 ? "成功" : "失敗";   }

修改之后代碼更簡潔一些。

④Spring 中的判斷

對于參數(shù)的異常,越早被發(fā)現(xiàn)越好,在 Spring 中提供了 Assert 用來幫助我們檢測參數(shù)是否有效。

public void save(Integer code,String name) {        if(code == null) {        throw Exception("code不能為空");           } else {          if(name == null) {              throw Exception("name不能為空");               } else {              System.out.println("doSave");          }      }  }

如果參數(shù)非常多的話,if...else 語句會很長,這時如果改成使用 Assert 類判斷,代碼會簡化很多:

public String save2(Integer code,String name) {            Assert.notNull(code,"code不能為空");       Assert.notNull(name,"name不能為空");       System.out.println("doSave");  }

“如惡化清除滿屏的if-else”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!


網(wǎng)站題目:如惡化清除滿屏的if-else
當(dāng)前路徑:http://weahome.cn/article/gssjie.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部