1.模板設計模式:
模板設計模式是一種常見的設計模式,主要作用是對 具體操作的 共有代碼塊進行提取,提升代碼復用性。
那么說道代碼復用性,首先想到的是抽象類而不是接口。
因為抽象類的本質就是為了代碼復用,抽象類既可以包含抽象方法也可以包含具體方法。
在模板設計模式中,我們將 需要將原本共有的具體操作抽離并封裝在抽象類的具體方法中。讓抽象類的具體操作來實現需要被復用的邏輯。而其余的抽象方法是不同業務的 個性,各個業務可以按照自己的方式進行重寫。這部分特性在模板設計模式中是為具體方法服務的。
2.開發優惠券推送功能
優惠券推送功能是根據excel導出方式來進行的。目前我們有一張優惠券,畫像平臺根據用戶特性選取出符合這張優惠券的用戶,從而導出一個excel表格,表格中裝入的是符合發券特征的用戶。我們的優惠券推送功能就是根據讀取excel表格中的用戶信息,將這張優惠券統一推送給目標用戶。
對于優惠券發放,我們考慮到了定時發放和立即發放兩種情況。由于定時發放使用傳統的定時任務需要建立線程定時去掃描全表,造成數據庫的較大開銷,所以考慮使用RocketMQ來進行定時任務。
RocketMQ的延時消息任務,需要發送地址、消息以及發送時間三個參數。
public SendResult syncSendDelayTimeMills(String destination, Message<?> message, long delayTime) {return this.syncSend(destination, message, (long)this.producer.getSendMsgTimeout(), delayTime, DelayMode.DELAY_MILLISECONDS);
}
這是對應的rocketMQ的定時消息發送接口,需要destination,message,delayTime
2.1發送地址
對于不同的業務,建立不同的group,消費者會根據group從消息隊列中接收自己想要的信息。
2.2消息
需要注意的是Message<?>是指上是Spring中的包import org.springframework.messaging.Message;
Message通過MessageBuilder進行構建,這部分內容就是消息實體。
2.3發送時間
delayTime就是指延遲發送的時間。
3.如何抽離出模板設計模式
由于我們的業務不僅有延時發送任務,還有立即發送任務,所以會為這兩種任務設計消息發送類AbstractCommonSendProduceTemplate,很顯然,這是共有的抽象類。
然后為不同的業務創建不同的實現類,繼承AbstractCommonSendProduceTemplate。
3.1如何判斷是立即發送還是延時發送?
我們只需要設計一個屬性,根據屬性的值來判斷即可。這可以解決立即發送和延時發送的矛盾。在業務層無需再進行判斷。
3.2具體如何完整實現模板設計模式?
在上面我們講解了類的抽離,我們現在需要找立即發送與延時發送的區別,抽離出共性與特性。
共性很顯然就是都需要使用rocketMQ進行消息發送。
1.特性:對于立即發送而言,需要的api不是syncSendDelayTimeMills而是syncSend,
public SendResult syncSend(String destination, Message<?> message, long timeout) {return this.syncSend(destination, message, timeout, 0);
}
timeout是超時時間。這是第一個特性。
2.處理的業務模塊不同,在項目中,推送優惠券模塊的推送功能可以是定時推送也可以是立即推送,包含這兩種方式。
而對于優惠券創建模塊的定時銷毀過期優惠券功能目前只需要定時任務方式。
所以對于不同的業務,我們需要抽離出不同的事件,因為不同的業務需要的參數不同,這里我們的項目定義了兩個事件類:CouponTaskExecuteEvent、CouponTemplateDelayEvent
基于上述的共性與特性,具體如何實現?
從頂層考慮,我們的目的是實現發送消息代碼的復用,所以我們抽離代碼的時候一般而言是先抽取主要邏輯,對應抽象類中的具體方法。
當具體方法因不同業務模塊需要不同參數的時候我們再使用抽象方法對”個性“進行實現即可。也就是上述內容所說的抽象方法為具體方法服務的思想。
因為定時和立即發送api不同,所以我們需要一個dto類來傳遞一個屬性來驗證是定時發送還是立即發送。
所以現在我們需要創建一個共有的DTO類來輔助具體任務的開發。DTO應該包含多個業務的主要內容,所以對于這種模板設計模式而言,盡量使業務功能相近,不然在DTO設計時不好設計。
public class BaseSendExtendDTO {/*** 事件名稱*/private String eventName;/*** 主題*/private String topic;/*** 標簽*/private String tag;/*** 業務標識*/private String keys;/*** 發送消息超時時間*/private Long sentTimeout;/*** 具體延遲時間*/private Long delayTime;
}
事件名稱用于分辨不同功能,主題用于不同消息類型的監聽,如果是立即發送,則delayTime為null,用于判斷信息類型。
需要注意的是,該DTO類只是用于輔助消息發送,和真正的業務無關。比如說用于判別目前的任務是那個業務模塊,執行業務模塊中的哪個任務,任務的信息發送是什么模式等等。
比如在:
public SendResult syncSendDelayTimeMills(String destination, Message<?> message, long delayTime) {
return this.syncSend(
destination, message,
(long)this.producer.getSendMsgTimeout(),
delayTime, DelayMode.DELAY_MILLISECONDS);
}
這個 發送api中,DTO類只控制destination與delayTime,而message是由事件決定的。
4.總結
通過上述DTO可以使得不同功能模塊找到自己的實現方式(比如立即發送和延時發送就是通過判別DTO中delayTime是否為null,再比如通過Topic使得不同消費者只監聽自己的內容)。
通過兩個事件類對兩個功能模塊所需屬性做了區分,實質上最終傳遞的內容就是對應的事件。