基于開閉原則優化數據庫查詢語句拼接方法

背景

在開發實踐中,曾有同事在實現新功能時,因直接修改一段數據庫查詢條件拼接方法的代碼邏輯,導致生產環境出現故障。

具體來看,該方法通過在函數內部直接編寫條件判斷語句實現查詢拼接,盡管從面向對象設計的開閉原則(OCP)出發,理想的代碼應滿足 “對修改封閉、對擴展開放”—— 即允許通過擴展而非修改原有邏輯來應對變化,但這一規范屬于非強制性設計原則,在實際開發中難以確保所有成員始終嚴格遵守,從而導致新增或調整查詢條件時,開發人員更傾向于直接修改原函數,而非通過擴展方式實現,最終埋下代碼變更的風險隱患。

func (m ActivityModel) buildQuery(ctx context.Context, db *gorm.DB, filter *ActivityListFilter) {if filter.Name != "" {db = db.Where("name like ?", "%"+filter.Name+"%")}if filter.StartAt > 0 {db = db.Where("start_at <= ?", filter.StartAt)}if filter.EndAt > 0 {db = db.Where("end_at >= ?", filter.EndAt)}if filter.Description != "" {db = db.Where("description like ?", "%"+filter.Description+"%")}if filter.CreatedBy != "" {db = db.Where("created_by like ?", "%"+filter.CreatedBy+"%")}db = db.Where("is_del = ?", filter.IsDel)if filter.CreatedAt > 0 {db = db.Where("create_time > ?", filter.CreatedAt)}if filter.UpdatedAt > 0 {db = db.Where("update_time > ?", filter.UpdatedAt)}if filter.DeletedAt > 0 {db = db.Where("delete_time > ?", filter.DeletedAt)}
}

上述代碼中,每個查詢條件的添加或修改都需直接操作?buildQuery?函數,違背了開閉原則。為降低維護風險并提升代碼擴展性,可通過設計模式將查詢條件的邏輯解耦,實現 “對擴展開放,對修改封閉” 的目標。

方案一:使用策略模式

策略模式可以將每個查詢條件封裝成獨立的策略,這樣在需要添加新的查詢條件時,只需新增一個策略類,而無需修改原有的代碼。

package mainimport ("context""github.com/jinzhu/gorm"
)// ActivityModel 定義活動模型
type ActivityModel struct{}// ActivityListFilter 定義過濾條件
type ActivityListFilter struct {Name        stringStartAt     int64EndAt       int64Description stringCreatedBy   stringIsDel       boolCreatedAt   int64UpdatedAt   int64DeletedAt   int64
}// QueryStrategy 定義查詢策略接口
type QueryStrategy interface {Apply(db *gorm.DB, filter *ActivityListFilter) *gorm.DB
}// NameQueryStrategy 實現名稱查詢策略
type NameQueryStrategy struct{}func (n NameQueryStrategy) Apply(db *gorm.DB, filter *ActivityListFilter) *gorm.DB {if filter.Name != "" {return db.Where("name like ?", "%"+filter.Name+"%")}return db
}// StartAtQueryStrategy 實現開始時間查詢策略
type StartAtQueryStrategy struct{}func (s StartAtQueryStrategy) Apply(db *gorm.DB, filter *ActivityListFilter) *gorm.DB {if filter.StartAt > 0 {return db.Where("start_at >= ?", filter.StartAt)}return db
}// 可以繼續為其他條件實現類似的策略// buildQuery 使用策略模式構建查詢
func (m ActivityModel) buildQuery(ctx context.Context, db *gorm.DB, filter *ActivityListFilter) *gorm.DB {strategies := []QueryStrategy{NameQueryStrategy{},StartAtQueryStrategy{},// 添加其他策略}for _, strategy := range strategies {db = strategy.Apply(db, filter)}return db.Where("is_del = ?", filter.IsDel)
}

在這個方案中,每個查詢條件都被封裝成一個獨立的策略,buildQuery?函數通過遍歷策略列表來應用這些策略。當需要添加新的查詢條件時,只需實現一個新的策略類并將其添加到策略列表中。

優勢

  • 解耦條件邏輯:每個策略類單一職責,聚焦特定條件處理,降低代碼耦合度。
  • 無縫擴展:新增查詢條件時,只需實現?QueryStrategy?接口并添加到策略列表,無需修改核心邏輯。
  • 便于測試:可獨立單元測試每個策略,提升測試覆蓋率和維護效率。

方案二:使用函數切片

你可以將每個查詢條件封裝成一個函數,并將這些函數存儲在一個切片中。這樣,在需要添加新的查詢條件時,只需添加一個新的函數到切片中。

package mainimport ("context""github.com/jinzhu/gorm"
)// ActivityModel 定義活動模型
type ActivityModel struct{}// ActivityListFilter 定義過濾條件
type ActivityListFilter struct {Name        stringStartAt     int64EndAt       int64Description stringCreatedBy   stringIsDel       boolCreatedAt   int64UpdatedAt   int64DeletedAt   int64
}// QueryFunc 定義查詢函數類型
type QueryFunc func(db *gorm.DB, filter *ActivityListFilter) *gorm.DB// buildQuery 使用函數切片構建查詢
func (m ActivityModel) buildQuery(ctx context.Context, db *gorm.DB, filter *ActivityListFilter) *gorm.DB {queryFuncs := []QueryFunc{func(db *gorm.DB, filter *ActivityListFilter) *gorm.DB {if filter.Name != "" {return db.Where("name like ?", "%"+filter.Name+"%")}return db},func(db *gorm.DB, filter *ActivityListFilter) *gorm.DB {if filter.StartAt > 0 {return db.Where("start_at >= ?", filter.StartAt)}return db},// 添加其他查詢函數}for _, queryFunc := range queryFuncs {db = queryFunc(db, filter)}return db.Where("is_del = ?", filter.IsDel)
}

在這個方案中,每個查詢條件都被封裝成一個匿名函數,并存儲在?queryFuncs?切片中。buildQuery?函數通過遍歷這個切片來應用這些查詢函數。當需要添加新的查詢條件時,只需添加一個新的匿名函數到切片中。

優勢

  • 輕量簡潔:無需定義額外接口或類,直接通過匿名函數實現條件封裝,適合簡單場景。
  • 靈活組合:可動態增刪條件函數,支持運行時根據業務需求調整查詢邏輯。
  • 代碼隔離:每個條件邏輯在獨立函數內實現,修改單個條件不會影響其他邏輯。

總結

這兩種方案都遵循了開閉原則,使得代碼在添加新的查詢條件時更加靈活,同時減少了修改現有代碼的風險。

  • 策略模式適合條件邏輯復雜、需要多維度擴展或復用的場景,通過接口化設計提升代碼規范性。
  • 函數切片則以更輕量的方式實現條件解耦,適合快速開發或條件相對固定的場景。

無論選擇哪種方案,核心目標都是將查詢條件的 “修改” 操作轉化為 “擴展” 操作 —— 新增條件時無需觸碰原有邏輯,從架構層面降低人為失誤導致的風險。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78472.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78472.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78472.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

QT開發工具對比:Qt Creator、Qt Designer、Qt Design Studio

前端開發工具—Qt Designer Qt Designer是Qt框架的一部分&#xff0c;是一個圖形用戶界面設計工具。它允許開發者通過可視化方式設計和布局GUI組件&#xff0c;而無需手動編寫UI代碼。設計完成后&#xff0c;Qt Designer生成UI文件&#xff08;通常以.ui為擴展名&#xff09;&…

0基礎 | STM32 | TB6612電機驅動使用

TB6612介紹及使用 單片機通過驅動板連接至電機 原因&#xff1a;單品機I/O口輸出電流I小 驅動板&#xff1a;從外部引入高電壓&#xff0c;控制電機驅動 電源部分 VM&#xff1a;電機驅動電源輸入&#xff0c;輸入電壓范圍建議為3.7&#xff5e;12V GND&#xff1a;邏輯電…

【操作系統】死鎖

1. 定義 死鎖是指兩個或多個進程&#xff08;或線程&#xff09;在執行過程中&#xff0c;因爭奪資源而造成的一種僵局&#xff0c;每個進程都無限期地等待其他進程釋放它們所持有的資源。在這種情況下&#xff0c;沒有任何進程能夠繼續執行&#xff0c;除非有外部干預。 2. …

C++入門?關于類的一些特殊知識點

涉及的關于類中的默認成員函數的知識點可以看我的這篇博客哦~ C入門必須知道的知識?類的默認成員函數&#xff0c;一文講透運用 目錄 初始化列表 類型轉換 static成員 友元 內部類 匿名對象 對象拷貝時的一些編譯器的優化 初始化列表 我們知道類中的構造函數的任務是完…

只用Prettier進行格式化項目

1.下載Prettier插件&#xff0c;禁用ESlint 2.在項目根目錄新建.prettierrc文件 {"singleQuote": true,"jsxSingleQuote": true,"printWidth": 100,"trailingComma": "none","tabWidth": 2,"semi": f…

XXL-TOOL v1.4.0 發布 | Java工具類庫

Release Notes 1、【新增】JsonRpc模塊&#xff1a;一個輕量級、跨語言遠程過程調用實現&#xff0c;基于json、http實現&#xff08;從XXL-JOB底層通訊組件提煉抽象&#xff09;。2、【新增】Concurrent模塊&#xff1a;一系列并發編程工具&#xff0c;具備良好的線程安全、高…

基于LVGL的登錄界面設計

目錄 一、演示 二、前言 三、部件知識 3.1 圖片按鈕部件 3.1.1 圖片按鈕部件的組成 3.1.2 圖片的來源 3.1.3 添加/清除的狀態 3.1.4 圖片按鈕部件 API 函數 3.2 鍵盤部件(lv_keyboard) 3.2.1 鍵盤部件的組成 3.2.2 鍵盤部件的相關知識 3.2.2.1 鍵盤部件模式 3.…

S3 跨賬戶復制:增強云中的災難恢復計劃

您準備好提升您的云和 DevOps 技能了嗎&#xff1f; &#x1f425;《云原生devops》專門為您打造&#xff0c;我們精心打造的 30 篇文章庫&#xff0c;這些文章涵蓋了 Azure、AWS 和 DevOps 方法論的眾多重要主題。無論您是希望精進專業知識的資深專業人士&#xff0c;還是渴望…

線程與進程深度解析:從fork行為到生產者-消費者模型

線程與進程深度解析&#xff1a;從fork行為到生產者-消費者模型 一、多線程環境下的fork行為與線程安全 1. 多線程程序中fork的特殊性 核心問題&#xff1a;fork后子進程的線程模型 當多線程程序中的某個線程調用fork時&#xff1a; 子進程僅包含調用fork的線程&#xff1…

Circular Plot系列(五): circle plot展示單細胞互作

這是我們circle系列的最后一節&#xff0c;我想常見的弦圖是繞不開的&#xff0c;所以最后從前面介紹的circle plot思路&#xff0c;做一遍弦圖。其實前面的內容如果消化了&#xff0c;plot互作弦圖也就不成什么問題了。 效果如下&#xff1a; #cellchat提取互作結果&#xff…

(11)Vue-Router路由的詳細使用

本系列教程目錄&#xff1a;Vue3Element Plus全套學習筆記-目錄大綱 文章目錄 第2章 路由 Vue-Router2.1 Vue路由快速入門2.1.1 創建項目2.1.2 路由運行流程 2.2 傳遞參數-useRoute2.2.1 路徑參數-params1&#xff09;普通傳參2&#xff09;傳遞多個參數3&#xff09;對象方式傳…

react + antd 實現后臺管理系統

文章目錄 完整路由搭建Layout 和 Aside組件引入 AntdAside組件實現 項目效果圖 項目完整代碼地址 https://gitee.com/lyh1999/react-back-management 項目完整代碼地址 react依賴安裝 最好采用yarn 安裝 react-router 安裝依賴 配置路由 history模式 / // src/router/…

基于AWS Marketplace的快速解決方案:從選型到部署實戰

1. 引言&#xff1a;為什么選擇AWS Marketplace&#xff1f; 在數字化轉型的背景下&#xff0c;企業需要快速獲取成熟的軟件工具和服務以降低開發成本。AWS Marketplace 作為亞馬遜云科技的官方應用商店&#xff0c;提供超過萬款預配置的第三方和AWS原生解決方案&#xff0c;涵…

2021年第十二屆藍橋杯省賽B組C++題解

2021年第十二屆藍橋杯省賽B組C題解 關鍵詞&#xff1a;藍橋杯、省賽、題解、C、算法 一、個人見解 第十二屆藍橋杯省賽B組共有10道題目&#xff0c;包含5道填空題&#xff08;T1-T5&#xff09;和5道編程題&#xff08;T6-T10&#xff09;&#xff0c;總分150分。比賽時長4小…

日語學習-日語知識點小記-進階-JLPT-N1階段(1):語法單詞

日語學習-日語知識點小記-進階-JLPT-N1階段&#xff08;1&#xff09;&#xff1a;語法單詞 1、前言&#xff08;1&#xff09;情況說明&#xff08;2&#xff09;工程師的信仰&#xff08;3&#xff09;高級語法N1語法和難點一、N1語法學習內容&#xff08;高級語法&#xff…

Python|Pyppeteer實現自動登錄小紅書(32)

前言 本文是該專欄的第32篇,結合優質項目案例持續分享Pyppeteer的干貨知識,記得關注。 本文中,筆者以小紅書為例,基于Pyppeteer實現自動登錄“小紅書”。 需要注意的是,對Pyppeteer不太熟悉的同學,可往前翻閱本專欄前面介紹的Pyppeteer知識點,本專欄將帶你了解并熟練使…

【翻譯、轉載】【轉載】LLM 的函數調用與 MCP

來源&#xff1a; https://www.dailydoseofds.com/p/function-calling-mcp-for-llms/ 【代碼以圖像顯示的是原文內容&#xff0c;以代碼形式顯示的是大模型給出的參考】 LLM 的函數調用與 MCP 在 MCP 變得像現在這樣主流&#xff08;或流行&#xff09;之前&#xff0c;大多…

【QT】QT中http協議和json數據的解析-http獲取天氣預報

QT中http協議和json數據的解析 1.http協議的原理2.QT中http協議的通信流程2.1 方法步驟 3.使用http協議&#xff08;通過http下載圖片和獲取天氣預報信息&#xff09;3.1 http下載網絡上的圖片(下載小文件)3.1.1 示例代碼3.1.2 現象 3.2 獲取網絡上天氣預報3.2.1 免費的天氣預報…

hot100:鏈表倒數k個節點- 力扣(LeetCode)

題目&#xff1a; 實現一種算法&#xff0c;找出單向鏈表中倒數第 k 個節點。返回該鏈表中倒數第k個節點。 示例一&#xff1a; 輸入&#xff1a;{1,2,3,4,5},2 返回值&#xff1a;{4,5} 說明&#xff1a;返回倒數第2個節點4&#xff0c;系統會打印后面所有的節點來比較。 …

Spring AI 實戰:第十一章、Spring AI Agent之知行合一

引言:智能體的知行辯證法 “知為行之始,行為知之成”,王陽明的哲學智慧在AI時代煥發光彩。智能體(LLM Agent)的進化之路,正是"認知-決策-執行"這一閉環的完美詮釋: 知明理:融合大語言模型的推理能力與知識圖譜的結構化認知行致用:基于ReAct模式的動態工具調…