Android 設計模式實戰之關於封裝計費代碼庫的策略模式詳談

来源:http://www.cnblogs.com/guanmanman/archive/2017/06/26/7080692.html
-Advertisement-
Play Games

一直以來都飽受公司APP客戶端關於各種計費點的折磨。一段時間內,同一應用或不同應用間接入多家的計費模式,然後需要在不同的計費間來回的跳轉,大大的增加了出錯的幾率,甚至有時候出現計費點錯亂的現象,基於這種困擾,一直以來都想封裝一套統一實現計費策略的代碼庫,最近正好有一套APP要實現微信,支付寶支付等計... ...


寫在之前

這周生活上出現了很多的不如意,從周一開始就覺得哪裡出現了問題,然後就是各種煩躁的情緒,後來事情還真是如預感的那樣發生了,很是心痛,但也無可奈何,希望大家都好好珍惜自己身邊的人:友人,親人,家人,願一切和睦。

正文

一直以來都飽受公司APP客戶端關於各種計費點的折磨。一段時間內,同一應用或不同應用間接入多家的計費模式,然後需要在不同的計費間來回的跳轉,大大的增加了出錯的幾率,甚至有時候出現計費點錯亂的現象,這就導致了工作效率的降低,而且做了大量的無用功,費時費力還沒有成果。

基於這種困擾,一直以來都想封裝一套統一實現計費策略的代碼庫,但是一直沒有著手去做。最近有一套APP要實現微信,支付寶支付等計費,那麼正好可以利用這個機會來實現一整套的計費點代碼庫。

而本篇博文的產生就是計費代碼庫的一個縮影,主要講解的是如何使用策略模式設計這種可以使用多種演算法來完成同樣的目標。

需求分析

下麵來簡單的看下需求:

本款APP要求能實現微信、支付寶等支付方式進行購買虛擬幣,購買完成後需上傳購買數量,同時要更新用戶所擁有的虛擬幣。

ok,我們來分析下需求,主要可以分三步:

首先,購買虛擬幣,這是一個動作,在這個動作中有可以分為多種形式,比如這裡的用微信和支付寶購買;

其次,購買完成後,要上傳服務端存儲用戶購買的虛擬幣數量;

最後是更新UI,顯示用戶目前擁有的虛擬幣。

由上面的分析,我們對需求有了很清晰的認識,這裡的主要任務是設計一個簡版的計費代碼庫,所以我們主要關心的也就是計費這一模塊,其他的部分我們並不能考慮到計費庫里,我相信大家都能明白,一個庫,乾好一件事即可。

說到計費,我們的需求中也就是購買虛擬幣,而購買虛擬幣這個行為可以是多種形式的,比如說使用微信,支付寶等,那麼各種支付方式是不是都是一樣的實現呢?

顯然不是,它們都有自己的實現方式,而且每一家也都有自己的計費流程等,所以我們的庫設計應該是可以符合多種實現的計費模式,並且能很好的實現擴展,而且各種實現可以互相替換,比如,購買虛擬幣能使用微信支付也能使用支付寶支付,這就實現了互相替換。那麼有沒有這麼一種實現方式呢?

顯然答案是有的,這就是我們要講的策略模式。

模式定義

那到底什麼是策略模式呢?

策略模式是定義了一族演算法,並分別將每組演算法封裝起來,使它們之間可以互相替換。演算法的變化獨立於使用演算法的用戶。

它主要使用在哪些場景呢?

①:同一種行為,多種實現。

②:安全地封裝多種同一類型的操作。

③:同一抽象類有多個子類,而又需要選擇具體子類操作。

由它的定義和使用場景,我們更加確信了我們的計費代碼庫使用這種模式是行得通的。

那麼,我們到底該怎麼使用策略模式進行設計我們的庫呢?

詳細設計

說道關於計費的問題,相信我們每個人都很清楚的瞭解,那就是需要有一個類似pay的方法專門用來進行支付,所以我們得有一個支付類,並且這個支付類帶有一個pay的支付方法,如下設計:

這裡我並沒有針對參數來進行詳細的構建,畢竟只是一個針對簡單的demo級別庫,主要還是用來學習策略模式的,所以,我這裡就只是簡單的設計一個String類型的url參數,並讓他返回一個String類型的結果,因為大多數網路請求都是返回的一個json串,便於解析。

可以看到我在這裡設計了一個基類BasePay,並帶有一個pay方法,接過相信支付功能的同學都應該知道,為了保證支付的安全性,很多支付渠道都會有一個預訂單的介面,在預訂單中返回一些重要的信息,併在支付介面中調用,例如微信支付就是這樣模式。

所以為了滿足這種需求,我們就需要有這麼一個預訂單的方法,那麼我們在我們的基類中添加上這種方法:

同樣的沒有做過多的參數考慮,只是讓他傳進一個String類型的URL地址。

ok,我們的基類已經設計出來了,那麼各種各種的支付都可以繼承此類來完成預訂單和支付的能力,那麼你覺得這樣的設計怎麼樣呢?

假如有一種支付是不需要預訂單呢?

這樣也很簡單,我就直接做一個空的實現。

沒錯,這種可以實現,那接入有100個支付,其中有80個沒有預訂單的實現呢?

難道你要做上80個空實現嗎?

顯然這是不可取的,那麼我們該怎麼做呢?

設計原則:保持共性,封裝變化

假如有80個支付渠道不需要預訂單,20個是需要預訂單的,由此可以看出這個預訂單的介面是變化的,而且剩下的20個需要預定單的每個實現也是不相同的,那麼我們根據面向對象的設計原則:把需要變化的部分給獨立的封裝起來,只保留相同的部分,那麼我們是不是可以把它給獨立的封裝起來以便應付隨時變化的實現呢?

同樣的道理支付介面的實現也是不盡相同的,是否也應該封裝起來呢?

由此想到了另外的一個設計原則。

設計原則:針對介面編程,而不是針對實現編程

針對介面編程,不針對具體的實現進行編程,這樣我們就可以區分不同的實現獨立的完成,同時每個支付的業務只面對介面,不用關心具體的實現是怎麼完成的:

由上圖所示,分別的定義了兩個介面PreOrderInterface和PayInterface,並分別包含一個方法,並且我們分別對這兩個介面做了兩個實現,分別是針對微信和支付寶的。

這樣一來的話,我們就把原來的BasePay裡面的兩個變化的方法分別的抽取出來封裝成介面,並根據不同的業務渠道進行實現。

那我們是不是可以直接用BasePay基類來實現這個兩個介面呢?

如果直接用BasePay來實現介面,那和不抽取變化封裝有什麼區別呢,所以我們不能直接用BasePay來或者是它的子類來直接的實現這兩個介面,那麼到底該怎麼運用這兩個介面呢?

由此我們想到了另外的一種設計原則:

設計原則:少用繼承,多用組合

可以使用組合的形式來添加對介面的運用,有了介面的引用,不僅可以包含了演算法的封裝,同時也可以在運行時動態的改變行為。

這樣我們就有了對這兩個介面的引用,那麼我們在定義兩個對介面調用的方法:

同時為了便於擴展,為了能在運行時改變我們的行為方式,我們可以用設置介面的方式來實現:

ok,這樣將會更加利於我們的擴展。下麵來看看完整的BasePay類吧:

這樣的話,當我們需要預訂單的時候直接的調用performPreOrder方法,在支付的時候調用performPay方法,可以完全的不用考慮它的直接實現到底是怎麼做的,我們只需要關心的就是調用的介面而已,從而降低了耦合性。

當然這隻是我們的基類,我們還需要它的具體實現類:

如果具體類有相同的功能,那麼可以在父類中定義一個抽象方法,同時改變父類為抽象類,那麼這個相同的功能就可以直接的在子類中實現,比如說要列印一個輸出支付結果的log日誌,那麼就可以分別在子類中完成。

ok,有了子類具體實現,那麼到底該怎麼使用呢:

其實也很簡單,既然父類已經有了對介面的引用,那麼我們可以在子類中對介面實例化:

這裡可以看出,當我們需要什麼的時候就進行什麼初始化,如果不需要,可以直接的不用管它。

那麼在來看看我們是怎麼使用的:

當我們確定要使用哪種支付方式時,可以利用面向對象多態的特性指定具體的子類,然後在子類中實例化父類對介面的具體引用實現,當使用支付介面時,可以直接的調用父類提供的支付方法完成支付。

父類只需要關心引用的介面,而不需要關心具體的介面實現,實現解耦;

子類只需要關係對父類引用介面的實例化,和所共有的特性實現,也不需要具體的實現;

對具體的實現進行了封裝,每種具體的實現類都實現介面,它只關註具體的實現,這樣就把整個變化封裝在特有的實現類中,通過介面獲取到對它的引用,那麼整個結構就顯得非常的清晰,各個模塊都只需要關註自己的領域,而且模塊間耦合性也降到最低。

把變化進行封裝,保持共性,通過介面制定具體的演算法,這就是我們的策略模式。

最後在來看下整個類圖:

ok,這樣我們就利用策略模式實現了一個簡單的計費代碼庫,每當有新的計費加入時,我們只需要添加具體的實現類和具體的支付類,並不需要修改原來的代碼,並且可以多方面復用。

到這裡基本的策略模式就講完了,計費代碼庫demo級也就出來了,當然它並不完善,只是關註策略模式的這一部分,其他的像網路請求,一些幫助類等都是需要封裝的,也不是這個主題所關註的,所以這就需要大家根據自己的需求來實現了。

好了,今天就講到這裡吧。

各位如果還有哪裡不明白的,或是我這裡講的還不夠透徹,亦或是講錯了的地方請留言指正,讓我們共同進步,謝謝

同時,請大家掃一掃關註我的微信公眾號,雖然寫的不是很勤,但是每一篇都有質量保證,讓您學習到真正的知識。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 感謝 LeaVerou 大神,讓我們可以提前使用上這麼美妙的屬性。 conic-gradient 是個什麼?說到 conic-gradient ,就不得不提的它的另外兩個兄弟: linear-gradient : 線性漸變 radial-gradient : 徑向漸變 說這兩個應該還是有很多人瞭解並 ...
  • 一.首先我們總結下行內元素和塊級元素有哪些: 行內元素: <a>標簽可定義錨<abbr>表示一個縮寫形式<acronym>定義只取首字母縮寫<b>字體加粗<bdo>可覆蓋預設的文本方向<big>大號字體加粗<br>換行<cite>引用進行定義<code>定義電腦代碼文本<dfn>定義一個定義項目< ...
  • 求出字元串中位的字元(charAt()方法、substr()方法)、刪除字元串中重覆的字元並輸出(push()方法、call()方法、filter()方法)。 ...
  • 在用Reactnative寫工程時,預設奇妙的有一種像OC中,或者Java 中或者當前類的私有屬性的想法,state 和props都不能滿足時,就是ref 它能達到其他語言中持有一個view組件,並且局部的刷新 ref 接受值為string類型的參數或者一個函數function 需要提醒大家的是,只 ...
  • 咱們今天還是輪播圖,今天說jquery的輪播圖! 首先,要有個插件: 請無視Zepto插件,他沒起到任何作用! 就是這兩個啦! 然後就是代碼! 就是這樣,你學會了嗎?? ...
  • “懶”是第一生產力。 代碼復用總是程式員喜聞樂見的,前端組件化的最終目的就是復用,今天我們就將深入探討如何實現UI組件的復用。 ...
  • 一、基本選擇器 1. * 通用元素選擇器,匹配任何元素 2. E 標簽選擇器,匹配所有使用E標簽的元素 3. .info class選擇器,匹配所有class屬性中包含info的元素 4. #footer id選擇器,匹配所有id屬性等於footer的元素 二、多元素的組合選擇器 5. E,F 多元 ...
  • 這篇文章主要分析網路請求和結果交付的過程。 NetWork工作原理 之前已經說到通過mNetWork.performRequest()方法來得到NetResponse,看一下該方法具體的執行流程,performRequest是一個介面方法,真正實現該方法以及被調用的是BasicNetWork,其具體 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...