自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

今天,我要干掉 if ... else ...

開(kāi)發(fā) 后端
對(duì)于目前的現(xiàn)狀來(lái)說(shuō),我如果在原有的基礎(chǔ)上來(lái)修改,只要稍微注意一下解決需求不是很大的問(wèn)題,但是說(shuō)后面可維護(hù)性非常差。

[[394207]]

業(yè)務(wù)背景

近日在公司領(lǐng)到一個(gè)小需求,需要對(duì)之前已有的試用用戶申請(qǐng)規(guī)則進(jìn)行拓展。我們的場(chǎng)景大概如下所示:

  1. if (是否海外用戶) { 
  2.  return false
  3. if (刷單用戶) { 
  4.   return false
  5. if (未付費(fèi)用戶 && 不再服務(wù)時(shí)段) { 
  6.   return false
  7. if (轉(zhuǎn)介紹用戶 || 付費(fèi)用戶 || 內(nèi)推用戶) { 
  8.   return true
  9. else { 
  10.   return false

按照上述的條件我們可以得出的結(jié)論是:

咱們的的主要流程主要是基于 and 或者 or 的關(guān)系。

如果有一個(gè)不匹配的話,其實(shí)咱們后續(xù)的流程是不用執(zhí)行的,就是需要具備一個(gè)短路的功能。

對(duì)于目前的現(xiàn)狀來(lái)說(shuō),我如果在原有的基礎(chǔ)上來(lái)修改,只要稍微注意一下解決需求不是很大的問(wèn)題,但是說(shuō)后面可維護(hù)性非常差。

后面進(jìn)過(guò)權(quán)衡過(guò)后,我還是決定將這個(gè)部分進(jìn)行重構(gòu)一下。

規(guī)則執(zhí)行器

針對(duì)這個(gè)需求,我首先梳理了一下咱們規(guī)則執(zhí)行器大概的設(shè)計(jì), 我們首先需要對(duì)規(guī)則進(jìn)行抽象, 然后定義規(guī)則模板,然后通過(guò)規(guī)則模板去自己實(shí)現(xiàn)具體的規(guī)則,最后對(duì)于規(guī)則中可能會(huì)存在共享對(duì)象的轉(zhuǎn)換,我們提前在模板方法中定義即可,后期如果需要的話,可以對(duì) DSL 語(yǔ)言或者增加腳本語(yǔ)言解析器,以及反射 class 文件的方式來(lái)實(shí)現(xiàn)動(dòng)態(tài)拓展。

最后我設(shè)計(jì)了一個(gè) V1 版本和大家一起分享一下,如果大家也有這樣的 case 可以給我分享留言,下面部分主要是設(shè)計(jì)和實(shí)現(xiàn)的流程和 code .

規(guī)則執(zhí)行器的設(shè)計(jì)

對(duì)于我規(guī)則的執(zhí)行器的設(shè)計(jì),我收到 <<策略模式>> 和 << 規(guī)約模式>> 的啟發(fā)。 在這個(gè)場(chǎng)景咱們首先想到的就是將規(guī)則的自然語(yǔ)言轉(zhuǎn)換為程序代碼。在 DDD 設(shè)計(jì)中,我們可以選擇 DSL 方式來(lái)處理 Rule 的一種方式;對(duì)于業(yè)務(wù)數(shù)據(jù)處理或者其他的復(fù)雜流程,我們可以通過(guò) Rule 模板來(lái)進(jìn)行自定義實(shí)現(xiàn)具體的 Rule 策略。

對(duì)于規(guī)則執(zhí)行器的處理步驟如下:

  1. 首先需要構(gòu)造業(yè)務(wù)數(shù)據(jù)如用戶基本,用戶狀態(tài),以及一些業(yè)務(wù)數(shù)據(jù);
  2. 然后通過(guò)當(dāng)前的上下文,獲取具體規(guī)則列表,這里可以從規(guī)則工廠中獲取;
  3. 然后調(diào)用規(guī)則執(zhí)行方法拿到結(jié)果。
  4. 在執(zhí)行的過(guò)程,對(duì)鏈接關(guān)系的處理,常用的關(guān)系有 and or not 等

抽象規(guī)則和定義模板

首先需要定義 BaseRule 作為 Rule 的一個(gè)抽象,定義 execute 方法為執(zhí)行方法。然后定義 AbstractRule

作為規(guī)則模板,作為一個(gè)方法的公共實(shí)現(xiàn),提供拓展點(diǎn) convert 、executeRule 可以用戶轉(zhuǎn)換自定義 RuleDto 數(shù)據(jù)結(jié)構(gòu)。 AddressRule 和 NationalityRule分別做為兩個(gè)實(shí)現(xiàn) Rule 的具體策略或者說(shuō)是具體實(shí)現(xiàn)。

  1. // 業(yè)務(wù)數(shù)據(jù) 
  2. @Data 
  3. public class RuleDto { 
  4.   private String address; 
  5.   private int age; 
  6.  
  7. // 規(guī)則抽象 
  8. public interface BaseRule { 
  9.  
  10.     boolean execute(RuleDto dto); 
  11.  
  12. // 規(guī)則模板 
  13. public abstract class AbstractRule implements BaseRule { 
  14.  
  15.     protected <T> T convert(RuleDto dto) { 
  16.         return (T) dto; 
  17.     } 
  18.  
  19.     @Override 
  20.     public boolean execute(RuleDto dto) { 
  21.         return executeRule(convert(dto)); 
  22.     } 
  23.    
  24.     protected <T> boolean executeRule(T t) { 
  25.         return true
  26.     } 
  27.  
  28. // 具體規(guī)則- 例子1 
  29. public class AddressRule extends AbstractRule { 
  30.  
  31.     @Override 
  32.     public boolean execute(RuleDto dto) { 
  33.         System.out.println("AddressRule invoke!"); 
  34.         if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) { 
  35.             return true
  36.         } 
  37.         return false
  38.     } 
  39.  
  40. // 具體規(guī)則- 例子2 
  41. public class NationalityRule extends AbstractRule { 
  42.  
  43.     @Override 
  44.     protected <T> T convert(RuleDto dto) { 
  45.         NationalityRuleDto nationalityRuleDto = new NationalityRuleDto(); 
  46.         if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) { 
  47.             nationalityRuleDto.setNationality(MATCH_NATIONALITY_START); 
  48.         } 
  49.         return (T) nationalityRuleDto; 
  50.     } 
  51.  
  52.  
  53.     @Override 
  54.     protected <T> boolean executeRule(T t) { 
  55.         System.out.println("NationalityRule invoke!"); 
  56.         NationalityRuleDto nationalityRuleDto = (NationalityRuleDto) t; 
  57.         if (nationalityRuleDto.getNationality().startsWith(MATCH_NATIONALITY_START)) { 
  58.             return true
  59.         } 
  60.         return false
  61.     } 
  62.  
  63. // 常量定義 
  64. public class RuleConstant { 
  65.     public static final String MATCH_ADDRESS_START= "北京"
  66.     public static final String MATCH_NATIONALITY_START= "中國(guó)"

規(guī)則執(zhí)行器的核心構(gòu)建

RuleService 是規(guī)則執(zhí)行和規(guī)則管道鏈接的具體類,在這個(gè)類里面我們首先提供了一個(gè)構(gòu)造器方法 create()可以提供默認(rèn)的初始化過(guò)程

  1. // 規(guī)則執(zhí)行器 
  2. public class RuleService { 
  3.  
  4.     private Map<Integer, List<BaseRule>> hashMap = new HashMap<>(); 
  5.     private static final int NOT = 2; 
  6.     private static final int AND = 1; 
  7.     private static final int OR = 0; 
  8.     private RuleDto ruleDto; 
  9.  
  10.     public static RuleService create(RuleDto ruleDto) { 
  11.         RuleService ruleService = new RuleService(); 
  12.         ruleService.ruleDto = ruleDto; 
  13.         return ruleService; 
  14.     } 
  15.  
  16.  
  17.     public RuleService and(List<BaseRule> ruleList) { 
  18.         hashMap.put(AND, ruleList); 
  19.         return this; 
  20.     } 
  21.  
  22.     public RuleService or(List<BaseRule> ruleList) { 
  23.         hashMap.put(OR, ruleList); 
  24.         return this; 
  25.     } 
  26.  
  27.     public RuleService not(List<BaseRule> ruleList) { 
  28.         hashMap.put(NOT, ruleList); 
  29.         return this; 
  30.     } 
  31.  
  32.     public boolean execute() { 
  33.         return this.execute(ruleDto); 
  34.     } 
  35.  
  36.     private boolean execute(RuleDto dto) { 
  37.         for (Map.Entry<Integer, List<BaseRule>> item : hashMap.entrySet()) { 
  38.             List<BaseRule> ruleList = item.getValue(); 
  39.             switch (item.getKey()) { 
  40.                 case AND
  41.                     // 如果是 and 關(guān)系,同步執(zhí)行 
  42.                     System.out.println("execute key = " + 1); 
  43.                     if (!andRule(dto, ruleList)) { 
  44.                         return false
  45.                     } 
  46.                     break; 
  47.                 case OR
  48.                     // 如果是 or 關(guān)系,并行執(zhí)行 
  49.                     System.out.println("execute key = " + 0); 
  50.                     if (!orRule(dto, ruleList)) { 
  51.                         return false
  52.                     } 
  53.                     break; 
  54.                 case NOT
  55.                     // 如果是 not 關(guān)系 
  56.                     System.out.println("execute key = " + 2); 
  57.                     if (!notRule(dto, ruleList)) { 
  58.                         return false
  59.                     } 
  60.                 default
  61.                     break; 
  62.             } 
  63.         } 
  64.         return true
  65.     } 
  66.  
  67.     private boolean andRule(RuleDto dto, List<BaseRule> ruleList) { 
  68.         for (BaseRule rule : ruleList) { 
  69.             boolean execute = rule.execute(dto); 
  70.             if (!execute) { 
  71.                 // and 關(guān)系匹配失敗一次,返回 false 
  72.                 return false
  73.             } 
  74.         } 
  75.         // and 關(guān)系全部匹配成功,返回 true 
  76.         return true
  77.     } 
  78.  
  79.     private boolean orRule(RuleDto dto, List<BaseRule> ruleList) { 
  80.         for (BaseRule rule : ruleList) { 
  81.             boolean execute = rule.execute(dto); 
  82.             if (execute) { 
  83.                 // or 關(guān)系匹配到一個(gè)就返回 true 
  84.                 return true
  85.             } 
  86.         } 
  87.         // or 關(guān)系一個(gè)都匹配不到就返回 false 
  88.         return false
  89.     } 
  90.  
  91.     private boolean notRule(RuleDto dto, List<BaseRule> ruleList) { 
  92.         // not 規(guī)則內(nèi)部為 and 鏈接 
  93.         return !andRule(dto, ruleList); 
  94.     } 
  95.  
  96. // 規(guī)則工廠類 
  97. public class RuleServices { 
  98.      
  99.     /** 
  100.      * 學(xué)生規(guī)則教研 
  101.      * 
  102.      * @return 
  103.      */ 
  104.     public static RuleService isValidStudent(RuleDto ruleDto) { 
  105.         AgeRule ageRule = new AgeRule(); 
  106.         NameRule nameRule = new NameRule(); 
  107.         NationalityRule nationalityRule = new NationalityRule(); 
  108.         AddressRule addressRule = new AddressRule(); 
  109.         SubjectRule subjectRule = new SubjectRule(); 
  110.         Flag110Rule flag110Rule = new Flag110Rule(); 
  111.  
  112.         return RuleService 
  113.                 .create(ruleDto) 
  114.                 .and(Arrays.asList(nationalityRule, nameRule, addressRule)) 
  115.                 .or(Arrays.asList(ageRule, subjectRule)) 
  116.                 .not(Collections.singletonList(flag110Rule)); 
  117.     } 

客戶端調(diào)用代碼

客戶端調(diào)用主要分為三個(gè)步驟:

首先是需要構(gòu)造業(yè)務(wù)數(shù)據(jù),因?yàn)橐?guī)則策略,是基于數(shù)據(jù)處理的。

然后從規(guī)則工廠中,獲取規(guī)則列表后返回規(guī)則定義執(zhí)行器。

最后執(zhí)行規(guī)則,返回結(jié)果。

  1. public class RuleServiceTest { 
  2.  
  3.     @org.junit.Test 
  4.     public void execute() { 
  5.         //規(guī)則執(zhí)行器 
  6.         //優(yōu)點(diǎn):比較簡(jiǎn)單,每個(gè)規(guī)則可以獨(dú)立,將規(guī)則,數(shù)據(jù),執(zhí)行器拆分出來(lái),調(diào)用方比較規(guī)整 
  7.         //缺點(diǎn):數(shù)據(jù)依賴公共傳輸對(duì)象 dto 
  8.  
  9.         //1. 構(gòu)造需要的數(shù)據(jù) create dto 
  10.         RuleDto dto = new RuleDto(); 
  11.         dto.setAge(5); 
  12.         dto.setName("張三"); 
  13.         dto.setAddress("北京"); 
  14.         dto.setSubject("數(shù)學(xué)");; 
  15.  
  16.         //2. 定義規(guī)則  init rule 
  17.         RuleService ruleService = RuleServices.isValidStudent(dto); 
  18.  
  19.         //3. 規(guī)則執(zhí)行 rule execute 
  20.         boolean ruleResult = ruleService.execute(); 
  21.         System.out.println("this student rule execute result :" + ruleResult); 
  22.     } 

總結(jié)

規(guī)則執(zhí)行器的優(yōu)點(diǎn)和缺點(diǎn)

優(yōu)點(diǎn):

  • 比較簡(jiǎn)單,每個(gè)規(guī)則可以獨(dú)立,將規(guī)則,數(shù)據(jù),執(zhí)行器拆分出來(lái),調(diào)用方比較規(guī)整;
  • 我在 Rule 模板類中定義 convert 方法做參數(shù)的轉(zhuǎn)換這樣可以能夠,為特定 rule 需要的場(chǎng)景數(shù)據(jù)提供拓展。

缺點(diǎn):上下游 rule 有數(shù)據(jù)依賴性,如果直接修改 dto 傳輸對(duì)象的值不是特別合理,這種建議采用中間數(shù)據(jù)存儲(chǔ)臨時(shí)數(shù)據(jù)。

參考資料

https://www.codenong.com/30430818

 

https://cloud.tencent.com/developer/article/1528935

 

責(zé)任編輯:武曉燕 來(lái)源: 運(yùn)維開(kāi)發(fā)故事
相關(guān)推薦

2020-04-09 08:29:50

編程語(yǔ)言事件驅(qū)動(dòng)

2021-01-29 07:45:27

if-else代碼數(shù)據(jù)

2020-10-22 09:20:22

SQLNoSQL 數(shù)據(jù)庫(kù)

2023-01-19 00:13:28

代碼技術(shù)計(jì)劃

2020-07-09 08:59:52

if else模板Service

2025-04-21 00:00:05

2019-03-14 09:18:19

5GWiFi4G

2019-04-25 14:25:24

Spring Bootif elseJava

2019-11-26 10:07:10

業(yè)務(wù)開(kāi)發(fā)邏輯

2025-03-12 14:09:56

2025-03-26 04:00:01

2022-06-14 10:49:33

代碼優(yōu)化Java

2021-10-27 09:10:50

CSS 技巧else

2019-10-22 20:12:22

戴爾

2021-04-27 08:25:52

MVCC數(shù)據(jù)MySQL

2019-10-22 09:11:50

策略業(yè)務(wù)代碼

2012-02-22 10:10:16

2022-08-10 19:28:40

Hadoop數(shù)據(jù)庫(kù)

2021-07-12 07:31:22

重構(gòu)軟件行業(yè)

2025-03-21 10:33:22

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)