歡迎光臨
每天分享高質量文章

按鈕條件邏輯配置化的可選技術方案

(點選上方公眾號,可快速關註)


來源:琴水玉 ,

www.cnblogs.com/lovesqcc/p/9568899.html

問題

詳情頁的一些按鈕邏輯,很容易因為產品的策略變更而變化,或因為來了新業務而新增條件判斷,或因為不同業務的差異性而有所不同。如果透過程式碼來實現,通常要寫一串if-elseif-elseif-else陳述句,且後續修改擴充套件比較容易出錯,需要重新釋出,靈活性差。 可採用配置化的方法來實現按鈕邏輯,從而在需要修改的時候只要變更配置即可。按鈕邏輯的程式碼形式一般是:

public Boolean getIsAllowBuyAgain() {

  if (ConditionA) {

    return BoolA;

  }

  if (ConditionB) {

    return BoolB;

  }

  

  if (CondtionC && !CondtionD && (ConditionE not in [v1,v2])) {

    return BoolC;

  }

  return BoolD;

}

本文討論了三種可選方案: 重量級的Groovy指令碼方案、輕量級的規則引擎方案、超輕量級的條件匹配運算式方案,重點講解了條件匹配運算式方案。

這裡的程式碼實現僅作為demo, 實際需要考慮健壯性及更多因素。 按鈕邏輯實現採用了“組合樣式”,解析配置採用了“策略樣式”和“工廠樣式”。

使用Groovy快取指令碼

優點:非常靈活通用,重量級配置方案

不足:耗時可能比較多,簡單script指令碼第一次執行比較慢, script指令碼快取後執行比較快, 可以考慮預熱; 複雜的程式碼不易於配置,簡單邏輯是可以使用Groovy配置的。

package button

 

import com.alibaba.fastjson.JSON

import org.junit.Test

import shared.conf.GlobalConfig

import shared.script.ScriptExecutor

import spock.lang.Specification

import spock.lang.Unroll

import zzz.study.patterns.composite.button.*

 

class ButtonConfigTest extends Specification {

 

    ScriptExecutor scriptExecutor = new ScriptExecutor()

    GlobalConfig config = new GlobalConfig()

 

    def setup() {

        scriptExecutor.globalConfig = config

        scriptExecutor.init()

    }

 

    @Test

    def “testComplexConfigByGroovy”() {

        when:

        Domain domain = new Domain()

        domain.state = 20

        domain.orderNo = ‘E0001’

        domain.orderType = 0

 

        then:

        testCond(domain)

    }

 

    void testCond(domain) {

        Binding binding = new Binding()

        binding.setVariable(“domain”, domain)

        def someButtonLogicFromApollo = ‘domain.orderType == 10 && domain.state != null && domain.state != 20’

        println “domain = ” + JSON.toJSONString(domain)

 

        (0..100).each {

            long start = System.currentTimeMillis()

            println “someButtonLogicFromApollo ? ” +

                    scriptExecutor.exec(someButtonLogicFromApollo, binding)

            long end = System.currentTimeMillis()

            println “costs: ” + (end – start) + ” ms”

        }

 

    }

}

 

class Domain {

 

    /** 訂單編號 */

    String orderNo

 

    /** 訂單狀態 */

    Integer state

 

    /** 訂單型別 */

    Integer orderType

 

}

package shared.script;

 

import com.google.common.cache.CacheBuilder;

import com.google.common.cache.CacheLoader;

import com.google.common.cache.LoadingCache;

import groovy.lang.Binding;

import groovy.lang.Script;

import org.apache.commons.pool2.impl.GenericObjectPool;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

import javax.annotation.Resource;

import shared.conf.GlobalConfig;

 

@Component(“scriptExecutor”)

public class ScriptExecutor {

 

  private static Logger logger = LoggerFactory.getLogger(ScriptExecutor.class);

 

  private LoadingCache

贊(0)

分享創造快樂