零基礎設計模式——總結與進階 - 2. 反模式

第五部分:總結與進階 - 2. 反模式 (Anti-Patterns)

在軟件開發中,我們追求良好的設計模式以構建健壯、可維護的系統。然而,同樣存在一些常見的、導致不良后果的解決方案,這些被稱為“反模式”。理解反模式,可以幫助我們識別并避免在項目中挖坑。

什么是反模式?

反模式描述了一種針對特定問題的、看似有效但實際上會導致更多問題的常見解決方案。它們通常源于缺乏經驗、錯誤的理解、時間壓力或不良的習慣。

1. 常見的反模式及其危害 (Common Anti-Patterns and Their Dangers)

讓我們通過生活中的例子來理解一些常見的反模式:

a. 上帝類 (God Class / God Object)

  • 描述:一個類知道或控制了系統中過多的其他類,集中了太多的職責和信息。它就像一個無所不能的“上帝”,什么都管。
  • 生活例子:想象一個家庭里,有一個“萬能家長”。這個家長不僅負責做飯、打掃、輔導孩子作業、修理電器、管理家庭財務,還負責所有對外聯絡、親戚朋友的人情往來等等。家里任何大小事務都必須經過他/她。
  • 危害
    • 高耦合、低內聚:上帝類與許多其他類緊密耦合,自身內部的職責也不單一,難以維護和修改。對上帝類的一點小改動都可能影響到很多其他部分。
    • 難以測試:由于職責過多,依賴復雜,測試上帝類變得非常困難。
    • 違反單一職責原則和開閉原則:明顯違反了SRP。當需要增加新功能或修改現有功能時,幾乎總是要修改這個上帝類,違反了OCP。
    • 團隊協作困難:多個人同時修改上帝類很容易產生沖突。
    • 生活中的危害:這個“萬能家長”會非常累,容易出錯。一旦家長生病或不在,整個家庭可能陷入混亂。其他家庭成員缺乏鍛煉和獨立性。

b. 意大利面條式代碼 (Spaghetti Code)

  • 描述:代碼結構混亂,控制流程像一碗意大利面條一樣隨意跳轉(例如,過多的 goto 語句,或者在面向對象語言中,對象之間隨意調用,缺乏清晰的層次和邊界)。
  • 生活例子:你正在組裝一個復雜的宜家家具,但說明書的步驟是混亂的:“先擰A螺絲,然后跳到第10步固定C板,再回到第3步安裝B滑軌,但如果D零件是藍色就跳到附錄2…” 你會發現自己在一堆零件和步驟中迷失方向。
  • 危害
    • 難以理解和維護:代碼邏輯難以追蹤,修改一處可能引發意想不到的連鎖反應。
    • 調試困難:當出現bug時,很難定位問題根源。
    • 復用性差:混亂的代碼塊很難被復用。
    • 生活中的危害:家具可能裝錯,或者裝到一半就放棄了。即使勉強裝好,結構也可能不穩定。

c. 熔巖流 (Lava Flow)

  • 描述:系統中存在大量“死代碼”或過時的、無人理解其用途但又不敢刪除的代碼塊(因為擔心刪除后系統會崩潰),就像凝固的熔巖一樣,堅硬、無用且阻礙前進。
  • 生活例子:你的車庫里堆滿了各種舊東西:壞掉的電器、幾十年前的雜志、用途不明的零件。你不敢扔掉它們,因為“萬一哪天用得上呢?”或者“這可能是某個重要東西的一部分”。結果車庫越來越擁擠,真正有用的東西反而沒地方放。
  • 危害
    • 增加系統復雜性:無用的代碼增加了理解和維護的負擔。
    • 隱藏風險:這些代碼可能包含未被發現的bug,或者與新代碼產生沖突。
    • 阻礙重構和優化:開發者因為害怕破壞未知邏輯而不敢進行必要的重構。
    • 生活中的危害:車庫無法有效利用,找東西困難,還可能存在安全隱患(如易燃物堆積)。

d. 復制粘貼編程 (Copy-and-Paste Programming / Duplicated Code)

  • 描述:當需要類似功能時,開發者簡單地從現有代碼中復制一段,然后稍作修改。這導致了大量重復或高度相似的代碼片段散布在各處。
  • 生活例子:你寫了一封邀請函。你的朋友也需要寫一封類似的,于是他直接復制了你的邀請函,只改了姓名和地址。后來,你發現邀請函上的某個重要信息(比如活動時間)寫錯了,你改了你自己的。但你朋友的那份復制品還是錯的,除非你特意通知他,并且他記得去改。
  • 危害
    • 維護噩夢:當需要修改這部分邏輯或修復bug時,必須找到所有復制粘貼的地方進行修改,很容易遺漏,導致不一致。
    • 代碼膨脹:不必要的代碼冗余增加了代碼庫的大小。
    • 違反DRY原則 (Don’t Repeat Yourself)
    • 生活中的危害:信息不一致導致誤解或問題。如果原始模板有缺陷,所有復制品都會繼承這個缺陷。

e. 船錨 (Boat Anchor / Dead Weight)

  • 描述:指系統中保留著一個過時的、不再使用或價值很低的硬件、軟件模塊或功能,但由于某些原因(如歷史遺留、政治因素、害怕移除的風險)而沒有被移除。它就像船錨一樣,拖慢了整個系統的發展。
  • 生活例子:你的公司還在使用一套非常老舊的財務軟件,它效率低下,與其他新系統不兼容,而且維護成本高昂。但因為“已經用了十幾年了”、“替換風險太大”、“某位元老堅持要用”,所以遲遲沒有升級或替換。
  • 危害
    • 拖累系統性能和可擴展性
    • 增加維護成本
    • 阻礙技術更新和創新
    • 生活中的危害:老舊的財務軟件可能導致財務處理效率低下,容易出錯,無法支持新的業務需求,最終影響公司發展。

f. 忙碌的旋轉 (Busy Spin / Busy Waiting)

  • 描述:一個進程或線程通過在一個循環中不斷檢查某個條件是否滿足來等待事件發生,而不是使用更有效的等待機制(如睡眠、阻塞、事件通知)。這會浪費CPU資源。
  • 生活例子:你在等一個重要的電話,但你沒有看來電顯示或鈴聲提醒。于是,你每隔幾秒鐘就拿起電話聽筒,看看有沒有人打進來,然后再放下。這樣你會一直很忙,而且可能錯過真正重要的事情。
  • 危害
    • 浪費CPU周期:即使沒有實際工作可做,CPU也在空轉。
    • 影響系統性能:其他需要CPU的進程可能得不到及時響應。
    • 可能導致系統不穩定
    • 生活中的危害:你無法專心做其他事情,而且效率低下。

g. 重新發明輪子 (Reinventing the Wheel)

  • 描述:花費時間和精力去創建一些已經有現成、成熟、經過測試的解決方案(如標準庫、第三方庫、常用算法)的功能。
  • 生活例子:你需要一個能切菜的工具。你沒有去買一把菜刀,而是決定自己從頭開始研究冶金、鍛造、開刃,試圖造出一把“完美”的刀。結果可能花費了大量時間,造出來的刀還不如市面上的好用。
  • 危害
    • 浪費開發資源和時間
    • 引入不必要的風險:自己實現的“輪子”可能不如現有的成熟方案健壯、高效或安全。
    • 可維護性差:團隊成員可能不熟悉你自創的“輪子”,增加了學習和維護成本。
    • 生活中的危害:耽誤了做飯的時間,而且可能因為刀不好用而切到手。

h. 貧血領域模型 (Anemic Domain Model)

  • 描述:領域對象(Domain Object)只包含數據(getter/setter方法),而沒有或很少有業務邏輯。業務邏輯被放在了服務類(Service Class)或過程腳本中。這些領域對象就像沒有血液的軀殼。
  • 生活例子:你有一個“病人”記錄卡,上面只有病人的姓名、年齡、病癥等數據。所有的診斷、開藥、治療方案等“行為”都不是由“病人”這個概念自身來驅動或封裝,而是由一個外部的“醫生工作站”程序來處理所有邏輯,病人記錄卡僅僅是數據的載體。
  • 危害
    • 面向過程而非面向對象:違背了面向對象將數據和行為封裝在一起的核心思想。
    • 領域邏輯分散:業務規則散落在各個服務類中,難以理解和維護領域模型的整體行為。
    • 領域對象表達能力弱:無法體現領域概念的真正含義和職責。
    • 生活中的危害:如果所有關于病人的智能都只在醫生工作站,那么病人記錄卡本身就失去了很多上下文和內在聯系,不利于信息的整體管理和決策支持。

2. 如何識別和避免反模式

識別和避免反模式需要經驗、良好的設計原則指導以及團隊的共同努力。

a. 識別反模式的信號:

  • 代碼異味 (Code Smells):如過長的方法、過大的類、重復代碼、復雜的條件語句、過多的參數等,這些往往是反模式存在的征兆。
  • 維護困難:如果修改一小部分代碼總是引發連鎖反應,或者添加新功能異常痛苦,可能存在反模式。
  • 測試困難:難以編寫單元測試或集成測試,通常意味著高耦合或職責不清。
  • 團隊抱怨:開發者經常抱怨某塊代碼難以理解、難以修改,或者某個模塊問題頻發。
  • 性能問題:不必要的資源消耗、響應緩慢等,可能與某些反模式(如忙碌旋轉)有關。

b. 避免反模式的策略:

  • 學習和理解設計原則 (SOLID等):這些原則是良好設計的基石,能幫助你從根本上避免反模式。
    • 生活例子:學習交通規則(設計原則)可以幫助你避免違章駕駛(反模式),從而保證行車安全和順暢。
  • 代碼審查 (Code Review):通過同行評審,可以發現潛在的反模式和代碼異味,集思廣益找到更好的解決方案。
    • 生活例子:寫完一篇文章后,請朋友幫忙校對(代碼審查),他們可能會發現你沒注意到的語病或邏輯不通順的地方(反模式)。
  • 重構 (Refactoring):定期對代碼進行重構,持續改進代碼結構,消除異味,將反模式轉化為良好的設計。
    • 生活例子:定期整理房間(重構),把亂放的東西歸位,扔掉不需要的雜物(消除反模式),讓房間保持整潔有序(良好設計)。
  • 使用成熟的框架和庫:避免重新發明輪子,利用社區驗證過的解決方案。
    • 生活例子:裝修時,選擇有良好口碑的裝修公司和品牌建材(成熟框架和庫),而不是凡事都自己DIY。
  • 小步快跑,持續集成/持續交付 (CI/CD):頻繁地集成和交付小的代碼塊,可以更早地發現和修復問題,避免問題累積成難以處理的反模式。
  • 自動化測試:編寫全面的單元測試、集成測試,確保代碼的正確性,也為重構提供了安全網。
  • 保持學習和反思:軟件開發技術和理念不斷發展,持續學習新的知識,反思項目中的經驗教訓,有助于提升識別和避免反模式的能力。
    • 生活例子:學車后,通過不斷練習和總結駕駛經驗(持續學習和反思),你會越來越熟練,能更好地應對各種路況,避免不安全駕駛行為。
  • 簡單設計 (Keep It Simple):在滿足需求的前提下,盡量保持設計簡單。不要為了炫技或過度預測未來而引入不必要的復雜性。

理解反模式與理解設計模式同樣重要。它們就像地圖上的“危險區域”標記,能幫助我們繞開陷阱,走向更健康、更可持續的軟件開發之路。

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

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

相關文章

音視頻流媒體高級開發-學習路線

原文作者:Linux 原文鏈接:音視頻流媒體高級開發-學習路線 如果你想往音視頻方向發展,那么本文一定要認真閱讀~ 大家都知道音視頻開發薪資高、門檻高、發展空間大,心里蠢蠢欲動,卻不知道怎么入門,怎么進階…

LINUX 通過rsync同步 免密備份

1,增加免密碼用戶密碼 useradd backup echo "5566777" | passwd --stdin backup echo "backup ALL(ALL) ALL" >> /etc/sudoers # 源服務器操作 ssh client_usersource_server ssh-keygen -t rsa # 一路回車 ssh-copy-id serv…

在使用 HTML5 的 <video> 標簽嵌入視頻時,有時會遇到無法播放 MP4 文件的問題

原因分析: 只能播放聲音,卻無法播放視頻。這通常是由于視頻編碼格式不兼容導致的。雖然 MP4 是一種常見的視頻格式,但它包含多種編碼方式,并非所有編碼方式都受 HTML5 支持。 解決方案: 確認視頻編碼格式: …

【bugfix】記一次Spring Boot 配置層級錯誤導致數據庫連接失敗

前言:為什么你的數據庫配置讀不到? 在 Spring Boot 項目中,配置文件的層級(prefix) 是決定屬性能否被正確解析的核心因素。一個看似微小的縮進錯誤,可能導致整個應用的數據庫連接失敗、服務啟動異常&#…

wpf 隊列(Queue)在視覺樹迭代查找中的作用分析

文章目錄 隊列(Queue)在視覺樹迭代查找中的作用分析示例代碼一、隊列的核心作用1. 替代遞歸的迭代機制2. 實現廣度優先搜索(BFS) 二、隊列的工作流程1. 初始化階段2. 處理循環 三、隊列操作的詳細步驟查找過程分解: 四、為什么使用隊列而不是其他數據結構1. 與棧(St…

快手數據開發面試SQL題:取窗口內排名第一和排名倒數第一的作為兩個字段輸出

目錄 問題描述 樣例數據表 sales 解決方案 第三步:使用條件聚合將多行合并為單行輸出" 步驟1:計算排名的中間結果 中間結果輸出: 步驟2:最終查詢(處理并列情況) 最終輸出結果: 關鍵點解釋: RANK() OVER (PARTITION BY group_id ORDER BY amount DESC):…

第十六屆藍橋杯國賽(2025)C/C++B組 藍橋星數字 獨家解析

這題我中午是12點以后開始做的,只剩下1個小時了,12點50的時候完成了框架,但是細節總是實現不對,現在晚上來復盤的時候才把這題A出來了。 但是,就像高考的導數你整個思路都會,你死在了求導上。。。&#xf…

Google 的 Protocol Buffers 介紹

Protocol Buffers(簡稱 Protobuf)是由 Google 開發的一種高效、靈活、跨語言的數據序列化協議,廣泛用于網絡通信、分布式系統、持久化存儲等場景。 一、什么是 Protocol Buffers? Protocol Buffers 是一種結構化的數據交換格式,類似于 XML 和 JSON,但更小、更快、更簡單…

犀思云Fusion WAN與阿里云NIS深度融合,實現端到端智能可觀測

隨著“AI數智化”浪潮逐步深入行業,企業網絡的復雜與故障感知日漸凸顯。如何實現網絡的高效運維、智能診斷與全域可視化管理,已成為企業上云的核心挑戰。 近日,犀思云與阿里云達成深度產品級合作,將阿里云網絡智能服務&#xff0…

基于gec6818的環境監測系統設計

一、設計要求 將環境中溫濕度數值、環境的光照強度和煙霧的信息獲取到開發板,顯示在圖形界面上。當溫度值高于閾值時,溫度指示燈變紅、蜂鳴器告警并且啟動直流電機正轉降溫;當濕度值高于閾值時,濕度指示燈變紅、蜂鳴器告警并且繼電器吸合接通…

c++中std::transform詳解和應用代碼示例

std::transform 是 C 標準庫中非常常用的算法之一&#xff0c;屬于 <algorithm> 頭文件。它的作用是將一個&#xff08;或兩個&#xff09;序列中的元素通過某個函數進行變換&#xff0c;并將結果輸出到另一個序列中。 一、std::transform 作用總結 std::transform 支持…

Yolov5 使用

1.開發背景 在已有的 Conda 環境下實現目標檢測標定。 2.開發需求 實現演示例子的圖片標定。 3.開發環境 Ubuntu20.04 Conda Yolov5 4.實現步驟 4.1 安裝環境 # 創建環境 python 版本建議 3.9 以上 conda create -n yolov5 python3.9# 進入環境 conda activate yolov5# …

資深Java工程師的面試題目(四)性能優化

以下是針對Java性能優化的面試題&#xff0c;涵蓋前后端技術棧的常見優化方式&#xff0c;適合評估候選人對性能調優的理解和實際應用能力&#xff1a; 1. JVM性能調優 題目: 請說明JVM垃圾回收&#xff08;GC&#xff09;的常見類型及其適用場景&#xff0c;并描述如何通過J…

火山引擎TTS使用體驗

文章目錄 前言1. 簡介1.1 能力體驗1.2 功能特性1.3 音色列表1.4 收費情況 2. 開啟服務2.1 創建應用2.3 使用服務介紹 3.Websocket接入演示3.1 編寫demo3.2 代碼解釋3.4運行demo 4. 參考鏈接 前言 語音合成TTS&#xff08;text to Speech&#xff09;是我覺得后續開發產品所不可…

Django中使用流式響應,自己也能實現ChatGPT的效果

最近在研究ChatGPT的時候&#xff0c;想通過openai提供的接口使國內用戶也可以無限制訪問&#xff0c;于是打算基于django開發一款應用。頁面的渲染也得想ChatGPT一樣采用流式響應&#xff0c;django中StreamingHttpResponse是支持流式響應的一種方式。 django 代碼 class Ch…

Python Redis 簡介

Redis 是一個高性能的內存鍵值數據庫&#xff0c;支持多種數據結構&#xff08;字符串、列表、哈希、集合等&#xff09;&#xff0c;常用于緩存、消息隊列和實時數據處理。Python 通過 redis-py 庫與 Redis 交互。 核心功能 內存存儲&#xff1a;數據存儲在內存中&#xff0c…

mac安裝whistle代理抓包工具(支持mock)

工具地址&#xff1a;https://wproxy.org/whistle/ 1、 安裝nodejs環境 參考方法&#xff1a;https://github.com/nvm-sh/nvm 1&#xff09;安裝 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash如圖&#xff0c;安裝成功 2&#xff09;…

基于 mydumper 實現 MySQL 定期全量備份、恢復方案

一、Mydumper 工具介紹 mydumper 是一款社區開源的邏輯備份工具,由 C 語言編寫,與 MySQL 官方提供的 mysqldump 相比,它具有更高的性能和更多的功能,例如: ? 支持多線程導出數據,速度更快; ? 支持一致性備份; ? 支持將導出文件壓縮,節約空間; ? 支持多線程恢復;…

C++中,std::async 一個用于異步編程的工具

在C中&#xff0c;std::async 是一個用于異步編程的工具&#xff0c;它允許你在一個單獨的線程中執行任務&#xff0c;并返回一個 std::future 對象&#xff0c;通過這個對象可以獲取任務的結果或者檢查任務的狀態。 基本用法1 lambda 表達式 #include <iostream> #incl…

【Linux驅動開發 ---- 4_驅動開發框架和 API】

Linux驅動開發 ---- 4_驅動開發框架和 API 目錄 Linux驅動開發 ---- 4_驅動開發框架和 API&#x1f3af; 目標&#xff1a;&#x1f4cc; 1. Linux 設備模型&#xff08;Linux Device Model&#xff09;**設備模型的核心概念**&#xff1a; &#x1f4cc; 2. 設備樹&#xff08…