您的位置:首頁 >聚焦 > 關(guān)注 >

從設計模式談業(yè)務開發(fā)

2023-06-27 13:03:58 來源:互聯(lián)網(wǎng)


(資料圖片)

阿里妹導讀

本文主要講述我們?nèi)绾瓮ㄟ^一個主干業(yè)務流程承接多個業(yè)務場景并在數(shù)據(jù)上可適配到多端型多場景,實現(xiàn)在服務端高質(zhì)量高效率的“包接口”。

一、背景

前臺業(yè)務同學在業(yè)務承接過程中總是抱怨大部分業(yè)務無法通過設計模式來承接,寫的代碼是越來越?jīng)]有追求,理由是我無法預測未來的業(yè)務的發(fā)展,且設計模式更多的是在框架或中間件中使用。然而設計模式是對能力抽象出的通用模式,從哲學的角度來看世間萬物皆塵土,事物都是可以抽象出共同的本質(zhì)的東西。所以,難道只有底層能力可以抽象,業(yè)務邏輯部分就不可以抽象了?必須可以才是啊。

在前臺業(yè)務承接過程中除了能力可以抽象,還有可以抽象出業(yè)務流程,假設在有這樣一些業(yè)務場景,品搜和圖搜、直播間評論和點贊、公域直播會場和私域商詳透直播等等,這些各領域內(nèi)的業(yè)務流程“大同小異”,因此都可以抽象出通用的業(yè)務流程節(jié)點。

但是通常在一個主干流程需要承接的場景有很多,比如直播間互動這個主干流程包括了直播間評論、點贊、求講解、看證書、進場等等場景,所以我們需要通過主要流程進行進行多場景承接。但是這樣還不夠,在面對多端型多場景的情況下需要處理返回不同的數(shù)據(jù)模型。

綜上所述,我們?nèi)绾瓮ㄟ^一個主干業(yè)務流程承接多個業(yè)務場景并在數(shù)據(jù)上可適配到多端型多場景,實現(xiàn)在服務端高質(zhì)量高效率的“包接口”,下面會詳細介紹。

二、業(yè)務承接

如果你面臨的問題是在同一個業(yè)務域上承接多種類似的業(yè)務場景,每天在適配各種端型或者各種場景而對外提供接口時,為了保證應用系統(tǒng)的可擴展性和高效承接業(yè)務,那么可以按照如下步驟進行設計。

2.1 業(yè)務流程抽象

首先需要進行業(yè)務建模,抽象出用戶用例或者user story,當然具體的粒度可以自己把控,具體如下:

2.1.1 用戶用例

在直播間互動領域內(nèi)的用戶用例如下:

?

從整個系統(tǒng)出發(fā),挖掘出面向不同的用戶提供的能力有哪些,在這些用例背后需要進行的流程和節(jié)點又是什么。通過這些流程和節(jié)點才能進行后續(xù)的系統(tǒng)時序和流程抽象,舉例如下

在互動領域內(nèi)的流程和節(jié)點如下:

風控檢查

評論持久化

評論上屏

評論進溝通

2.2.2 系統(tǒng)時序

基于用戶用例進行分析,這些用例都需要經(jīng)過什么的流程節(jié)點進行處理,然后將這些流程按照系統(tǒng)時序進行呈現(xiàn)。

到此基于上述的用例和時序是不是可以抽象出具體互動流程了,顯而易見。

2.2.3 業(yè)務流程抽象

有了系統(tǒng)用例和系統(tǒng)時序這一步就比較簡單,從系統(tǒng)時序里很容易可以抽象出具體的流程和流程中的處理節(jié)點,具體如下:

對于直播間互動領域可以抽象出的業(yè)務流程:風控檢查->互動內(nèi)容持久化-》消息上屏-》互動進IM

對于直播間分發(fā)領域可以抽象出的業(yè)務流程:直播推薦-》直播間基礎信息-》直播流信息-》直播間品信息

到此,大家可以按照上述步驟在大腦里對自己的業(yè)務域進行抽象出來了。

2.2.4 設計模式固化主流程

按照業(yè)務主流程可以通過模板模式將處理流程固定下來,如下所示:

@Override@LiveLog(logResult = true)public InteractionResult interactionSubmit(MobileInteractionRequest request, InteractionLiveRoom liveRoom) { Boolean needSave = MapUtils.getBoolean(request.getExtInfo(), LiveInteractionConstant.NEED_SAVE); // 默認保存 InteractionResult saveResult = null; if (Objects.isNull(request.getExtInfo()) || Objects.isNull(needSave) || needSave) { saveResult = save(request, liveRoom); if(Objects.nonNull(saveResult) && !saveResult.isSuccess()) { return saveResult; } } // 默認進溝通 InteractionResult chatResult; if (Objects.isNull(request.getSendToChat()) || Boolean.parseBoolean(request.getSendToChat())) { chatResult = sendToChat(request); if(Objects.nonNull(chatResult) && !chatResult.isSuccess()) { return chatResult; } } if(Objects.nonNull(saveResult) && saveResult.isSuccess()) { return saveResult; } return null;}/** * 互動行為保存到數(shù)據(jù)庫或者緩存中 * * @param request * @return */protected abstract InteractionResult save(MobileInteractionRequest request, InteractionLiveRoom liveRoom);/** * 進溝通 * * @param request * @return */protected abstract InteractionResult sendToChat(MobileInteractionRequest request);

2.2 業(yè)務流程擴展

因在上述模版模式中預留了兩個擴展點,所以在子類中可以通過擴展點進行擴展,舉例如下:?

?

如果有更多的場景就需要擴展實現(xiàn)上述兩個擴展點進行擴展即可,這樣保證了業(yè)務的高效承接。這里會有兩個問題:

在程序運行時如何根據(jù)具體的場景選擇哪個子類進行邏輯處理

如何進行適配端和場景返回的數(shù)據(jù)模型

針對第一個問題,其實就是如何去if else的問題,這里也給出比較經(jīng)典的方案:

枚舉法

表驅(qū)動法

策略模式+工廠模式

其中枚舉法和表驅(qū)動法比較簡單易用,原理就是將映射關(guān)系封裝在枚舉類或本地緩存中,這里簡單介紹下如何通過策略模式消除if else。

// 策略接口public interface Opt { int apply(int a, int b);}// 策略實現(xiàn)類@Component(value = "addOpt")public class AddOpt implements Opt { @Autowired xxxAddResource resource; // 這里通過Spring框架注入了資源 @Override public int apply(int a, int b) { return resource.process(a, b); }}// 策略實現(xiàn)類@Component(value = "devideOpt")public class devideOpt implements Opt { @Autowired xxxDivResource resource; // 這里通過Spring框架注入了資源 @Override public int apply(int a, int b) { return resource.process(a, b); }}// 策略處理@Componentpublic class OptStrategyContext{ private Map strategyMap = new ConcurrentHashMap<>(); @Autowired public OptStrategyContext(Map strategyMap) { this.strategyMap.clear(); this.strategyMap.putAll(strategyMap); } public int apply(Sting opt, int a, int b) { return strategyMap.get(opt).apply(a, b); }}?

總結(jié)偽代碼:

// 抽象類固定業(yè)務流程 預留擴展點public abstract class AbstractXxxx { doXxx(Object context) { // 節(jié)點1 doNode1(context); // 節(jié)點2 doNode2(context); // 節(jié)點3 doNode3(context); // 節(jié)點n ... } // 擴展點1 protected abstract Result doNode1(Object context); // 擴展點2 protected abstract Result doNode2(Object context); // 擴展點3 protected abstract Result doNode3(Object context);} // 策略處理public class OptStrategyContext{ private Map strategyMap = new ConcurrentHashMap<>(); static { // 上述模版模式的實現(xiàn)類 strategyMap.put("business1", Xxxx1); strategyMap.put("business2", Xxxx2); strategyMap.put("business3", Xxxx3); } // 初始化 public OptStrategyContext(Map strategyMap) { this.strategyMap.clear(); this.strategyMap.putAll(strategyMap); } public int doXxxx(Object context) { return strategyMap.get(business).doXxxx(context); }}

2.3 多場景多端型適配

上面我們只是通過模版模式抽象出了主干業(yè)務流程,但是如何適配不同的端型和不同的場景,返回不同的數(shù)據(jù)模型呢,這里有兩種答案,一種是模版模式、另一種是“棒棒糖”模式,下面逐一介紹。

2.3.1 模版模式適配

既然是模版模式,這里的主干流程又是什么呢?主要跟我們解決的問題有關(guān)系,按照2.1中的流程步驟,可以抽象出固定的流程為:請求入?yún)⑻幚?》業(yè)務邏輯處理-》結(jié)果返回處理。

其中業(yè)務邏輯處理可以選定為2.2中介紹的通過策略模式選擇業(yè)務擴展的子類,來處里業(yè)務部分;請求入?yún)⒑徒Y(jié)果返回處理部分可以設置為擴展點,供子類擴展。具體偽代碼如下:

// 抽象類固定業(yè)務流程 預留擴展點 適配多端型多場景public abstract class AbstractSceneAdapter { T doXxx(Object context) { // 節(jié)點1 doRequestFilter(context); // 節(jié)點2 getBusinessService(context).doBusiness(context); // 節(jié)點3 return doResultWrap(context); } // 擴展點1 protected abstract Result doRequestFilter(Object context); // 擴展點2 protected abstract Result doBusiness(Object context); // 擴展點3 protected abstract Result doResultWrap(Object context); // 業(yè)務邏輯處理子類 protected abstract BusinessService getBusinessService(Object context);} // 策略處理 根據(jù)不同端型場景選擇合適的子類public class SceneAdapterViewService { private Map strategyMap = new ConcurrentHashMap<>(); static { // 上述模版模式的實現(xiàn)類 strategyMap.put("scene1", Xxxx1); strategyMap.put("scene2", Xxxx2); strategyMap.put("scene3", Xxxx3); } // 初始化 public SceneAdapterViewService(Map strategyMap) { this.strategyMap.clear(); this.strategyMap.putAll(strategyMap); } public Result doXxxx(Object context) { return strategyMap.get(scene).doXxxx(context); }}

注:因要適配不同端型不同場景返回不同的數(shù)據(jù)模型,所以上述偽代碼中主流程最終返回的結(jié)果是一個泛型,在子類實現(xiàn)的時候進行確定具體返回的類型。

2.3.1 棒棒糖模式適配

通過模版模式來適配時會有一個小問題,當需要有多個請求入?yún)⑻幚砥骰蛘叨鄠€結(jié)果包裝器的時候需要在模版里增加處理節(jié)點,但其實這些節(jié)點是有共性的可抽象出來的。因此可以針對入?yún)⑻幚砥骱徒Y(jié)果包裝器定義單獨的接口,需要多個處理器時同時實現(xiàn)接口進行處理。然后這些實現(xiàn)類打包放在單獨的類中依次執(zhí)行即可。當然其中的業(yè)務處理部分也可以定義接口動態(tài)實現(xiàn)。偽代碼如下:

// 入?yún)⑻幚砥鱬ublic interface IRequestFilter<> { void doFilter(T t);}// 結(jié)果包裝器public interface IResultWrapper { Result doWrap(Result res);}public class SceneAdapterViewService implements InitializingBean { private List filters; private List wrappers; private Map strategyMap = new ConcurrentHashMap<>(); // 請求過濾器實現(xiàn)類 @Autowired @Qualifier("filter1") private IRequestFilter filter1; @Autowired @Qualifier("filter2") private IRequestFilter filter2; // 結(jié)果處理器實現(xiàn)類 @Autowired @Qualifier("wrapper1") private IResultWrapper wrapper1; // 業(yè)務處理實現(xiàn)類 @Autowired @Qualifier("scene1") private SceneAdapter scene1; @Autowired @Qualifier("scene2") private SceneAdapter scene2; @Autowired @Qualifier("scene3") private SceneAdapter scene3; // 主方法 publice Result sceneAdapte(Object context) { // 請求入?yún)⑦^濾 異常時返回 for(int i = 0; i

三、接口設計

基于上述兩種設計模式來適配時我們的接口又該如何設計,是設計面向通用的業(yè)務層接口還是面向定制化的業(yè)務接口,兩種方式各有優(yōu)缺點:

優(yōu)點

缺點

通用業(yè)務接口

1,擴展性強

2,業(yè)務承接效率高,無需頻繁發(fā)布代碼

1,業(yè)務邊界不清晰,問題排查效率低

2,接口數(shù)據(jù)冗余

定制化業(yè)務接口

1,業(yè)務邊界清晰

2,接口出入?yún)?shù)據(jù)無冗余

1,無擴展

2,頻繁包接口發(fā)布代碼

對于接口提供者來說肯定不希望頻繁改動代碼發(fā)布代碼,但是又希望能夠在業(yè)務承接過程中能夠高效適配多端型多場景,因此這里總結(jié)了下接口設計原則:

1、對于越底層的接口應該越通用,例如HSF接口、領域服務、中間件提供的接口;

2、對于越上層的接口應該越定制化,例如對于不同的UI適配、不同的場景適配等;

3、對于業(yè)務領域內(nèi)的接口應該通用化,例如直播業(yè)務域的分發(fā)領域、互動領域內(nèi)的接口盡可能的通用化;

四、總結(jié)

在承接業(yè)務過程中會面臨頻繁包接口、一個view層的數(shù)據(jù)模型充滿了小100個屬性,系統(tǒng)的擴展性遇到瓶頸,這些問題除了通過平臺化配置化的能力來解決,但是回歸到代碼本身我們?nèi)稳豢梢酝ㄟ^抽象的設計模式來解決。

基于抽象的理論達到復用、高內(nèi)聚低耦合,降低系統(tǒng)復雜度的目標,設計模式不只是用在底層能力或中間件中,在業(yè)務承接過程中亦有大的功效。

千萬不要為了用設計模式而刻意使用設計模式,帶來的效果適得其反,在選擇設計模式時也要三思,落地后再改動成本將會巨大。

在前臺業(yè)務開發(fā)中,需要劃分主各個業(yè)務領域,在領域中抽象出該業(yè)務的處理流程,基于流程可設計相關(guān)的擴展和編排能力,方式有很多種,包括SPI、設計模式、DSL等,本文主要通過模版模式和棒棒糖模式來解決問題。

接口設計應該按照越底層越通用,越上層越定制化的原則進行設計,當然在業(yè)務域內(nèi)的接口應盡可能的通用話。

阿里云開發(fā)者社區(qū),千萬開發(fā)者的選擇

阿里云開發(fā)者社區(qū),百萬精品技術(shù)內(nèi)容、千節(jié)免費系統(tǒng)課程、豐富的體驗場景、活躍的社群活動、行業(yè)專家分享交流,歡迎點擊【閱讀原文】加入我們。