我們在《SqlSugar開發框架》中,有時候都會根據一些需要引入一些設計模式,主要的目的是為瞭解決問題提供便利和代碼重用等目的。而不是為用而用,我們的目的是解決問題,併在一定的場景下以水到渠成的方式處理。不過引入任何的設計模式,都會增加一定的學習難度,除非是自己本身領會比較好了,就會顯得輕鬆一些。本... ...
我們在《SqlSugar開發框架》中,有時候都會根據一些需要引入一些設計模式,主要的目的是為瞭解決問題提供便利和代碼重用等目的。而不是為用而用,我們的目的是解決問題,併在一定的場景下以水到渠成的方式處理。不過引入任何的設計模式,都會增加一定的學習難度,除非是自己本身領會比較好了,就會顯得輕鬆一些。本篇隨筆抽取一些應用場景來介紹相關設計模式,有些地方如列舉有一定的偏頗之處,還請告知以便斧正。
1、Winform的本地訪問和基於Web API的訪問方式
Winform中的界面展示,以及數據處理,都需要具體實現的支撐,由於本身IOC控制反轉的介面設計,我們對具體數據的訪問,也是基於特定的介面層進行調用的,具體的實現,則是在程式啟動的時候,註入對應的介面實現即可。
以上的業務介面層和數據處理層分開,數據處理層會根據配置信息採用不同的資料庫實現方式,如可能是基於SQLServer、Oracle、Mysql、SQLite、PostgreSQL等不同的資料庫,這種方式是軟體開發中常見的一種原則——介面與實現分離的原則,也稱為介面隔離原則(Interface Segregation Principle,ISP)。
介面隔離原則是面向對象設計中的一項原則,它主張一個類不應該強迫其用戶依賴於它們不需要的方法。簡單來說,就是應該將一個介面拆分為多個較小的介面,這樣客戶端只需要知道與其相關的介面即可,而不需要瞭解其他介面的細節。
介面與實現分離的設計模式有很多,常見的包括:
-
工廠模式(Factory Pattern):工廠模式通過定義一個創建對象的介面,但是讓子類決定實例化哪個類。這樣,一個類的實例化延遲到其子類。
-
抽象工廠模式(Abstract Factory Pattern):抽象工廠模式提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。
-
適配器模式(Adapter Pattern):適配器模式允許將一個類的介面轉換成客戶希望的另外一個介面,使得原本由於介面不相容而不能一起工作的類可以一起工作。
-
代理模式(Proxy Pattern):代理模式為其他對象提供一種代理以控制對這個對象的訪問。代理對象在客戶端和目標對象之間起到中介作用。
在我們有些情況下,不是直接訪問具體的本地資料庫,有可能是間接調用Web API的介面服務的,而我們使用的時候,為了方便,可能需要進行一定的封裝處理,如下圖示。
如果我們這裡增加一個對Web API的調用,那麼在這裡註冊的時候,切換向Web API代理的註冊介面就可以,如下圖所示。
因此原來的Winform界面上的調用代碼,不需要任何變化,只需要註入不同的介面實現,就能獲得不同的方式:普通訪問資料庫方式,還是分散式獲取服務WebAPI的處理方式。
通過切換開關變數的方式,客戶可以非常方便的自由切換不同的數據訪問方式。數據提供服務,可以是直接訪問資料庫的方式,也可以是遠端的Web API服務方式,從而實現更加廣泛的業務需求。
2、基於介面和基類的繼承方式簡化重覆代碼
基於介面和基類的繼承方式不是特定的設計模式,而是一種面向對象設計的基本原則和實踐。
這種方式通常用於實現多態性(Polymorphism)、抽象化(Abstraction)和代碼重用。在面向對象的編程語言中,通過定義介面(Interface)和基類(Base Class),可以實現一種規範化的編程模式,讓代碼更加靈活、可擴展和易於維護。
這種方式的優點包括:
-
多態性: 通過介面和基類,不同的子類可以實現相同的介面或繼承相同的基類,從而可以以統一的方式對待不同的對象。
-
代碼重用: 可以將通用的功能和行為定義在介面或基類中,從而使得子類可以重用這些功能和行為,減少重覆代碼的編寫。
-
解耦和模塊化: 介面和基類可以幫助解耦不同模塊之間的依賴關係,提高代碼的模塊化程度,使得系統更易於理解和維護。
雖然基於介面和基類的繼承方式不是一個獨立的設計模式,但它是很多設計模式的基礎,比如工廠模式、策略模式、模板方法模式等都會使用到介面和基類的繼承方式。
在隨筆《基於SqlSugar的開發框架循序漸進介紹(5)-- 在服務層使用介面註入方式實現IOC控制反轉 》我們介紹過具體實現類的繼承關係,一般都是構建相應的基類和介面,然後才是具體的業務實現和介面,這樣處理可以重用基類的很多介面,提高代碼的重用效率。
而對應Web API的代理調用類,那麼為了極大的重用常規的介面處理,我們需要類似的繼承關係。
而在Web API的服務端中,我們為了重用,也是以基類和介面的方式來統一處理相關的邏輯。如我們根據項目的需要,定義了一些Web API控制器的基類,用於實現不同的功能。
同樣,BS的前端和移動端,我們根據框架後端的介面進行前端JS端的類的封裝處理,引入了ES6類的概念實現業務基類介面的統一封裝,簡化代碼。
許可權模塊我們涉及到的用戶管理、機構管理、角色管理、菜單管理、功能管理、操作日誌、登錄日誌等業務類,那麼這些類繼承BaseApi,就會具有相關的介面了,如下所示繼承關係。
按照這個思路,我們在BaseApi的ES6類裡面定義了對應Web API基類裡面的操作方法,如下所示。
這樣,我們在創建一個業務類的時候,如果沒有特殊的自定義介面,只需要繼承基類BaseApi即可具有所有的常規基類方法了。
3、簡單工廠設計模式
簡單工廠模式(Simple Factory Pattern)是一種創建型設計模式,它提供了一個統一的介面來實例化一組相關或相似的對象,而無需暴露對象的創建邏輯給客戶端。
簡單工廠模式包含以下幾個角色:
-
工廠(Factory): 負責創建具體產品的類。它通常包含一個或多個靜態方法,根據客戶端的參數來決定創建並返回哪種具體產品的實例。
-
產品介面(Product Interface): 聲明瞭具體產品類的共同介面,客戶端通過這個介面與具體產品類進行交互。
-
具體產品(Concrete Products): 實現了產品介面的具體類,是工廠創建的目標對象。
簡單工廠模式的核心思想是將對象的創建和使用進行分離,客戶端只需要知道使用工廠提供的介面來獲取所需的產品,而無需瞭解產品是如何被創建的。這樣的設計使得系統更加靈活,可以隨時更改具體產品的創建方式而不影響客戶端的代碼。
在基於《SqlSugar開發框架》中,我們設計了一些系統服務層的基類,在基類中會有很多涉及到相關的數據處理操作的,如果需要跟蹤具體是那個用戶進行操作的,那麼就需要獲得當前用戶的身份信息,包括在Web API的控制器中也是一樣,需要獲得對應的用戶身份信息,才能進行相關的身份鑒別和處理操作。
為了方便獲取用戶身份的信息,我們定義一個介面 IApiUserSession 如下所示。
/// <summary> /// API介面授權獲取的用戶身份信息-介面 /// </summary> public interface IApiUserSession { /// <summary> /// 用戶登錄來源渠道,0為網站,1為微信,2為安卓APP,3為蘋果APP /// </summary> string Channel { get; } /// <summary> /// 用戶ID /// </summary> int? Id { get; } /// <summary> /// 用戶名稱 /// </summary> string Name { get; } /// <summary> /// 用戶郵箱(可選) /// </summary> string Email { get; } /// <summary> /// 用戶手機(可選) /// </summary> string Mobile { get; } /// <summary> /// 用戶全名稱(可選) /// </summary> string FullName { get; } /// <summary> /// 性別(可選) /// </summary> string Gender { get; } /// <summary> /// 所屬公司ID(可選) /// </summary> string Company_ID { get; } /// <summary> /// 所屬公司名稱(可選) /// </summary> string CompanyName { get; } /// <summary> /// 所屬部門ID(可選) /// </summary> string Dept_ID { get; } /// <summary> /// 所屬部門名稱(可選) /// </summary> string DeptName { get; } /// <summary> /// 把用戶信息設置到緩存中去 /// </summary> /// <param name="info">用戶登陸信息</param> /// <param name="channel">預設為空,用戶登錄來源渠道:0為網站,1為微信,2為安卓APP,3為蘋果APP </param> void SetInfo(LoginUserInfo info, string channel = null); }
IApiUserSession的一個空白介面定義,它需要依賴於具體的介面實現,我們具體會使用基於Principal或者緩存方式實現記錄用戶身份的信息實現,如下是它們的類關係。
在客戶端和Web API的交換信息過程中,通過JWT的令牌方式,可以攜帶一些相關的用戶身份信息。
在登錄授權的這個時候,控制器會把相關的Claim信息寫入到token中的,我們在客戶端發起對控制器方法的調用的時候,這些身份信息會轉換成對象信息。
在監視視窗中查看IApiUserSession對象,可以查看到對應的信息。
簡單工廠的設計模式,是比較經常用到的一種設計模式,如我在隨筆《基於SqlSugar的開發框架循序漸進介紹(26)-- 實現本地上傳、FTP上傳、阿裡雲OSS上傳三者合一處理》中介紹到,根據配置信息來確定上傳的處理路徑選擇,就是一種簡單的工廠設計模式。
文件上傳處理應該由程式進行配置,決定使用那種方式,那麼這裡面我們為了彈性化處理, 在文件上傳模塊中採用選項模式【Options】處理常規上傳和FTP文件上傳的配置參數信息。
微軟引入選項模式,它是用於配置框架服務使用的設置. 選項模式由Microsoft.Extensions.OptionsNuGet包實現,除了ASP.NET Core應用,它還適用於任何類型的應用程式,如果需要瞭解,微軟的文檔詳細解釋了選項模式。
選項模式的限制之一是你只能解析(註入) IOptions <MyOptions>
併在依賴註入配置完成(即所有模塊的ConfigureServices
方法完成)後獲取選項值。如果你正在開發一個模塊,可能需要讓開發者能夠設置一些選項,併在依賴註入註冊階段使用這些選項. 你可能需要根據選項值配置其他服務或更改依賴註入的註冊代碼。IOptions<>是單例,因此一旦生成了,除非通過代碼的方式更改,它的值是不會更新的。
在本地文件處理過程中,如果是Web API方式調用服務層,那麼就在Web API所在的文件系統中,如果是Winform界面直接調用服務層,那麼就是在當前系統中處理文件,這種方式可以有效的管理我們的文件信息。
在FTP文件處理過程中,則是根據選項參數的信息,調用FluentFTP類庫進行文件的上傳操作。
在OSS對象存儲處理過程中,我們一般基於阿裡雲、騰訊雲等這些雲服務OSS的處理方式,一般它們會提供相應開發語言的SDK,我們引用併進行整合即可。
對於阿裡雲的OSS來說,對應的AccesKey和SecretKey自己可以通過查看賬戶的信息可以獲取到。
以上就是一些場景的應用設計模式,當前開發框架裡面,有很多其他的場景也同樣會引入一些不同的處理方法,不過主旨都是希望採用較小的代價和難度,來解決複雜的問題的思路。
鏈接附註:
如對我們的代碼生成工具有興趣,可以到官網下載使用《代碼生成工具Database2Sharp》。
如需瞭解我們官網對《SqlSugar開發框架》的介紹,可以參考《SqlSugar開發框架》瞭解。
如需閱讀我們對於《SqlSugar開發框架》文章介紹,可以參考博客園的隨筆標簽《SqlSugar隨筆 , WPF隨筆》學習瞭解。
專註於代碼生成工具、.Net/.NetCore 框架架構及軟體開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架等框架產品。
轉載請註明出處:撰寫人:伍華聰 http://www.iqidi.com