<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          多條件判斷場景中規(guī)則執(zhí)行器的設(shè)計(jì)

          共 5260字,需瀏覽 11分鐘

           ·

          2022-01-09 11:46

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

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

          if (是否海外用戶) {
          return false;
          }

          if (刷單用戶) {
          return false;
          }

          if (未付費(fèi)用戶 && 不再服務(wù)時(shí)段) {
          return false
          }

          if (轉(zhuǎn)介紹用戶 || 付費(fèi)用戶 || 內(nèi)推用戶) {
          return true;
          }
          復(fù)制代碼

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

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

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

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

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

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

          針對(duì)這個(gè)需求,我首先梳理了一下咱們規(guī)則執(zhí)行器大概的設(shè)計(jì), 然后我設(shè)計(jì)了一個(gè) V1 版本和大家一起分享一下,如果大家也有這樣的 case 可以給我分享留言,下面部分主要是設(shè)計(jì)和實(shí)現(xiàn)的流程和 code .

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

          對(duì)于規(guī)則的抽象并實(shí)現(xiàn)規(guī)則

          // 業(yè)務(wù)數(shù)據(jù)
          @Data
          public class RuleDto {
          private String address;
          private int age;
          }

          // 規(guī)則抽象
          public interface BaseRule {

          boolean execute(RuleDto dto);
          }

          // 規(guī)則模板
          public abstract class AbstractRule implements BaseRule {

          protected T convert(RuleDto dto) {
          return (T) dto;
          }

          @Override
          public boolean execute(RuleDto dto) {
          return executeRule(convert(dto));
          }

          protected boolean executeRule(T t) {
          return true;
          }
          }

          // 具體規(guī)則- 例子1
          public class AddressRule extends AbstractRule {

          @Override
          public boolean execute(RuleDto dto) {
          System.out.println("AddressRule invoke!");
          if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
          return true;
          }
          return false;
          }
          }

          // 具體規(guī)則- 例子2
          public class NationalityRule extends AbstractRule {

          @Override
          protected T convert(RuleDto dto) {
          NationalityRuleDto nationalityRuleDto = new NationalityRuleDto();
          if (dto.getAddress().startsWith(MATCH_ADDRESS_START)) {
          nationalityRuleDto.setNationality(MATCH_NATIONALITY_START);
          }
          return (T) nationalityRuleDto;
          }


          @Override
          protected boolean executeRule(T t) {
          System.out.println("NationalityRule invoke!");
          NationalityRuleDto nationalityRuleDto = (NationalityRuleDto) t;
          if (nationalityRuleDto.getNationality().startsWith(MATCH_NATIONALITY_START)) {
          return true;
          }
          return false;
          }
          }

          // 常量定義
          public class RuleConstant {
          public static final String MATCH_ADDRESS_START= "北京";
          public static final String MATCH_NATIONALITY_START= "中國";
          }
          復(fù)制代碼

          執(zhí)行器構(gòu)建

          public class RuleService {

          private Map> hashMap = new HashMap<>();
          private static final int AND = 1;
          private static final int OR = 0;

          public static RuleService create() {
          return new RuleService();
          }


          public RuleService and(List ruleList) {
          hashMap.put(AND, ruleList);
          return this;
          }

          public RuleService or(List ruleList) {
          hashMap.put(OR, ruleList);
          return this;
          }

          public boolean execute(RuleDto dto) {
          for (Map.Entry> item : hashMap.entrySet()) {
          List ruleList = item.getValue();
          switch (item.getKey()) {
          case AND:
          // 如果是 and 關(guān)系,同步執(zhí)行
          System.out.println("execute key = " + 1);
          if (!and(dto, ruleList)) {
          return false;
          }
          break;
          case OR:
          // 如果是 or 關(guān)系,并行執(zhí)行
          System.out.println("execute key = " + 0);
          if (!or(dto, ruleList)) {
          return false;
          }
          break;
          default:
          break;
          }
          }
          return true;
          }

          private boolean and(RuleDto dto, List ruleList) {
          for (BaseRule rule : ruleList) {
          boolean execute = rule.execute(dto);
          if (!execute) {
          // and 關(guān)系匹配失敗一次,返回 false
          return false;
          }
          }
          // and 關(guān)系全部匹配成功,返回 true
          return true;
          }

          private boolean or(RuleDto dto, List ruleList) {
          for (BaseRule rule : ruleList) {
          boolean execute = rule.execute(dto);
          if (execute) {
          // or 關(guān)系匹配到一個(gè)就返回 true
          return true;
          }
          }
          // or 關(guān)系一個(gè)都匹配不到就返回 false
          return false;
          }
          }

          復(fù)制代碼

          執(zhí)行器的調(diào)用

          public class RuleServiceTest {

          @org.junit.Test
          public void execute()
          {
          //規(guī)則執(zhí)行器
          //優(yōu)點(diǎn):比較簡單,每個(gè)規(guī)則可以獨(dú)立,將規(guī)則,數(shù)據(jù),執(zhí)行器拆分出來,調(diào)用方比較規(guī)整
          //缺點(diǎn):數(shù)據(jù)依賴公共傳輸對(duì)象 dto

          //1. 定義規(guī)則 init rule
          AgeRule ageRule = new AgeRule();
          NameRule nameRule = new NameRule();
          NationalityRule nationalityRule = new NationalityRule();
          AddressRule addressRule = new AddressRule();
          SubjectRule subjectRule = new SubjectRule();

          //2. 構(gòu)造需要的數(shù)據(jù) create dto
          RuleDto dto = new RuleDto();
          dto.setAge(5);
          dto.setName("張三");
          dto.setAddress("北京");
          dto.setSubject("數(shù)學(xué)");;

          //3. 通過以鏈?zhǔn)秸{(diào)用構(gòu)建和執(zhí)行 rule execute
          boolean ruleResult = RuleService
          .create()
          .and(Arrays.asList(nationalityRule, nameRule, addressRule))
          .or(Arrays.asList(ageRule, subjectRule))
          .execute(dto);
          System.out.println("this student rule execute result :" + ruleResult);
          }
          }
          復(fù)制代碼

          總結(jié)

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

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

            1. 比較簡單,每個(gè)規(guī)則可以獨(dú)立,將規(guī)則,數(shù)據(jù),執(zhí)行器拆分出來,調(diào)用方比較規(guī)整;

            2. 我在 Rule 模板類中定義 convert 方法做參數(shù)的轉(zhuǎn)換這樣可以能夠,為特定 rule 需要的場景數(shù)據(jù)提供拓展。

          • 缺點(diǎn):上下 rule 有數(shù)據(jù)依賴性,如果直接修改公共傳輸對(duì)象 dto 這樣設(shè)計(jì)不是很合理,建議提前構(gòu)建數(shù)據(jù)。


          作者:掘金老鄭
          鏈接:https://juejin.cn/post/6951764927958745124
          來源:稀土掘金
          著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。



          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲成人免费观看 | 无码流出在线观看 | 国产青娱乐在线视频 | 五月婷婷综合一区 | 亚洲无在线 |