版權聲明:本文爲博主原創文章,未經博主容許不得轉載。關注公衆號 技術匯(ID: jishuhui_2015) 可聯繫到做者。數據庫
優惠券系統的核心在於各類券種的管理,發放和使用。編程
一般的設計角度是從終端用戶出發,所謂「所見即所得」,終端用戶所見到的形形色色的優惠券,正是開發整個系統的挑戰所在。app
能夠想象,爲了配合不一樣形式的線上、線下活動,優惠券系統勢必有較大的改動,如何最大限度的下降改動的成本,成爲了最核心的挑戰。框架
就上述問題而言,解決的方法就是:規則與執行相隔離。編程語言
規則層,便是各種優惠券的使用限制,以及能達到的效果。ui
執行層,能夠理解爲根據規則計算最終成交價格。設計
對於規則層,筆者並不想將其上升到規則引擎的高度,只作適當的抽象。何況市面上的規則引擎開發框架未必能知足優惠券這一複雜的應用場景。cdn
值得注意的是,優惠券不等同於任何形式的優惠促銷活動,但倒是整個營銷系統的一部分。相較於優惠券,促銷活動系統的實現還要更困難。本文旨在闡述怎麼開發一個優惠券系統,促銷活動的設計與實現不在本文的範疇了。對象
在生成優惠券以前,咱們先來了解一下『優惠券模板』的概念。blog
顧名思義,按照模板去生成優惠券。
就比如工業生產流水線上的模具,只需注入原材料進行加工,便可製成成品。
所以,模板上攜帶了大量優惠券相關的信息,包括但不限於名稱、時效性、各種優惠規則,以及優惠券面額等,模板自己也有標題,狀態,建立人等基本信息。
當須要生成優惠券的時候,指定是哪套模板,而後填寫準備要生成的券總數便可,亦可在生成券的環節,指定接收對象,將券的派發操做一併完成。
可能讀者不由會發問了:這樣設計彷佛有些多餘,券模板和券實體重合的屬性不少,何不直接跳過券模板的環節,直接生成優惠券呢?
這樣作的緣由有兩個:
其一,不想重複輸入相同的優惠券信息,只要輸入一遍模板信息,便可實現批量生成券,能提升運營人員的工做效率;
其二,建立券模板和發送券實體是有兩類不一樣權限的人完成的。可能更高權限的運營人員能掌握着建立模板的權限,普通的運營人員則只須要按模板發優惠券便可。
以下圖,可反映出券模板和券實體的關係:
上圖涉及的內容基本上都能一目瞭然,接下來咱們將重點放在優惠規則的設計上。
優惠規則無疑是優惠券系統的核心部分,能不能最大限度的適應市場運營需求,就看優惠規則實現得怎麼樣了。
顯然,用窮盡法去實現市面上的優惠規則是不明智。
正所謂「世上惟一不變的就是變」,咱們必須提煉出優惠規則的本質,才能「以不變應萬變」。
筆者對市面上常見的優惠規則進行了調研,並結合自身業務需求,能夠將優惠規則大體分紅兩大類:
一、計算型規則。形如「無門檻直降20元」,「滿xx減xx」等,這些規則都暴露給終端用戶,是顯而易見的,讓用戶知曉這個優惠券是如何參與計算。
二、限制型規則。相較於計算型規則,限制型規則大多數狀況下是隱性的。好比:限制某些用戶領取,限制某套券模板最多能發放多少金額的優惠券,限制優惠券的渠道等。這類規則能夠很好的支撐平常的運營工做。
「萬物相生相剋」,衆多的優惠規則,也並非都能共存的,這裏就引入了規則『互斥性』的概念。當一個優惠規則與另外一個優惠規則不能同時存在於一套模板裏的時候,咱們就認爲這兩個規則是互斥的,這在設計規則的時候也須要有所考慮。
其次,優惠規則也會講究前後順序,因此必然就帶來了一個優惠規則的『優先級』屬性,咱們約定,數字越小,表示越優先,也就是按從小到大的順序。
如下給出一張完整的規則表,信息量較大,筆者將作必要的解釋。
規則表中,渠道限制、對象限制、金額限制和數量限制四者皆屬於限制型規則,優先級排在了較前面。同時,也給出了參數說明,規則描述,相對於模板的關係以及互斥規則,這些都是一目瞭然的。
接下來的扣減規則和封頂規則同屬於計算型規則,也算是優惠券的重中之重了。
筆者着重解釋一下滿減規則中的「階梯滿減」。咱們日常會看到有這類說法:每滿100元減10元,言下之意即是:滿100元減10元,滿200減20,以此類推,筆者將其稱之爲「階梯滿減」規則。
規則表中有涉及好多數字,筆者設計了一套生成規則。
規則編號是int型,Java 編程語言中,int全長 32位,以下圖所示:
一、第一位是符號位,固定爲0,且不容許出現 32位全是0的狀況,即爲正整數;
二、高8位是規則組別編號,理論上容許的數值範圍是0~255,可是實際的業務規則是假設最多有15組優惠規則,每組優惠規則編號取10的倍數,範圍即爲 10~150;
三、第10位和11位做爲備用,暫無實際用處,固定爲00;
四、中間15位,存放規則組下的細則編號,容許的範圍0~32767,可是實際業務規則是要達到兩兩互斥的目的,取值以下(以四位二進制爲例):
0001
0010
0100
1000
結論:排除全爲0的狀況,那麼有N位,就有N組兩兩互斥。若是組內組外互斥都考慮,那麼可取值就更少了;
五、末6位存放規則組的優先級,容許的值範圍是0~63,實際取值從1開始,考慮到以後會插入其餘的規則組,會在每兩個規則組別直接預留兩個級別,初始的優先級設置爲1,4,7,10,13,16…;
六、按照上述規則,根據既定的組別和優先級能夠生成上表中的細則編號。
渠道限制 83888577
0 00001010 00 000000000100111 000001
用戶類型限制 167775300
0 00010100 00 000000000110001 000100
指定用戶限制 167776900
0 00010100 00 000000001001010 000100
總金額限制 251660487
0 00011110 00 000000000100011 000111
單位金額限制 251662535
0 00011110 00 000000001000011 000111
總量限制 335545290
0 00101000 00 000000000001111 001010
我的所獲限制 335544778
0 00101000 00 000000000000111 001010
無門檻直減 419430989
0 00110010 00 000000000001001 001101
滿減 419431565
0 00110010 00 000000000010010 001101
打折 419436813
0 00110010 00 000000001100100 001101
封頂規則 503323024
0 00111100 00 000000001100110 010000
在作程序設計以前,咱們必須把握住關於優惠券的三個主要動做:
一、管理。指的是對券模板的建立,規則設置,關閉等操做。固然,在給模板設置規則參數的時候,須要校驗規則參數的合理性。
二、派發/領取。筆者將這兩個操做進行了合併,二者的區別無非就是有沒有綁定終端用戶,在接口層面是能夠合併的。一般,限制型規則會在此發揮做用,當觸發了這兩個操做的其中一個,在生成優惠券以前都將會先用限制型規則進行校驗。
三、使用。就是將優惠券花出去,計算型規則會在此發揮做用,主要是判斷滿不知足券的使用條件,計算減免金額等。
綜上,程序設計就靠這三個動做進行延展。
咱們先來設計一下規則層。
根據規則表中定義的一系列規則,反映在程序中能夠有兩種形式:
一種是使用配置文件(一般是XML),而後程序去解析;
另外一種則是直接使用枚舉類(或者其餘形式的類)。
第一種開發難度稍大,想作得比較強大的話,是須要花費很多功夫的。
對於優惠規則的定義和實現都是事先內置在程序中的,並非非專業人員改變一下配置文件就能達到效果的。
因此基於此考慮,使用了第二種實現方式。以下所示即爲規則定義:
Rulers含有五種重要的屬性:規則編號(ruleNo),規則名稱(ruleName),排序(sort),對應的Model Class對象,以及實現特定接口的serviceName。
接下來的三個方法也較爲重要:經過規則編號直接找到對應的枚舉,判斷是不是計算型規則,規則是否有多參數,和券模板是1~*的關係就表示是多參數。
固然,也少不了持久化到數據庫的各種Beans,每一個Bean都會繼承一個叫做SuperRule的抽象類,子類的屬性都是規則表中說起到的。Rulers中的Model Class就是來自於此。因爲規則較多,下面只展現SuperRule:
由於將規則分紅了兩大類,天然而然的就能派生出兩個Service,分別對應計算型規則和限制型規則。
最後一個是對規則參數的校驗,使用了泛型R,繼承自SuperRule。
至此,接口的設計就囊括了上述所說的三種優惠券相關的操做,也就意味着,若是出現了一個新的規則,至多實現上述的三個Service(由於可能有既是限制型規則,又是計算型規則),不過大多數狀況只要實現兩個Service,而後在Rulers配置好此新規則便可。至於規則基本的CRUD操做,只要繼承AbstractCouponRuleService,不須要額外花精力去實現。
這麼多規則,天然是須要一個『工廠類』進行調度的,好比生成一個規則Bean實例,生成一個Service實例。
本文從業務設計,到程序設計,對優惠券系統作了一個比較全面清晰的闡述,若是讀者正好也須要研發一個優惠券系統,這篇文章將會是很好的參考。