23種設計模式的優點與缺點概況

設計模式

標簽(空格分隔): 設計模式優點 應用場景


整理自《設計模式之禪》

單例模式

優點:

  • 只有一個實例,減少了內存開支;
  • 可以避免對系統資源的多重占用;
  • 可以在系統中設置全局的訪問點,優化和共享資源訪問;

缺點:

  • 沒有接口,擴展困難;
  • 對測試開發不利;

應用場景:

  • 要求生成唯一序列號的場景;
  • 需要一個共享訪問點;
  • 創建一個對象需要消耗過多的資源時
  • 需要定義大量的靜態常量和靜態方法時(也可直接聲明為static的方式);

工廠方法模式

優點:

  • 良好的封裝性,代碼結構清晰;
  • 擴展非常好;
  • 屏蔽產品類;

應用場景:

  • 是new一個對象的替代品;
  • 需要靈活的,可擴展的框架時;
  • 使用在測試驅動開發的框架下;

抽象工廠模式

優點:

  • 封裝性;
  • 產品族內部的約束為非公開狀態;

缺點:

  • 產品族擴展困難;

模板方法模式

優點:

  • 封裝不變部分,擴展可變部分,把不變的算法封裝到父類實現,可變的部分則通過繼承來擴展;
  • 提取公共部分代碼,便于維護;
  • 行為由父類控制,子類實現;

缺點:

  • 子類對父類產生影響,子類執行的結果影響了父類的結果;

應用場景:

  • 多個子類有公有的方法,且邏輯相同時;
  • 重要,復雜的算法,可以把核心算法設計為模板方法;
  • 重構時,把相同的代碼抽取到父類,然后通過鉤子函數結束其行為;

建造者模式

優點:

  • 封裝性,使得客戶端不必知道產品內部的組成細節,我們不用關心每一個具體的模型內部是如何實現的。
  • 建造者獨立,容易擴展
  • 便于控制細節風險,由于具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模塊產生任何影響;

建造者模式的應用場景:

  • 相同的方法,不同的執行順序,會產生不同的結果時;
  • 多個部件或零件,都可以裝配到一個對象中,但產生的運行結果又不相同時,如Android中的AlertDialog的構造;
  • 產品類非常復雜,或產品類的的調用順序不同產生不同的效果;

代理模式

優點:

  • 職責清晰,其實的角色就是實現實際的業務的邏輯,不用關心其他非本職責的事務;
  • 高擴展性,具體主題角色隨時都會發生變化,但只要它實現了接口,我們的代理類就可以在完全不做任何修改的情況下使用;

原型模式(通過實現Cloneable接口)

優點:

  • 性能優良,原型模式是在內存二進制流的拷貝,要比直接new一個對象性能好,特別是要在循環體內產生大量對象時,
  • 避免構造函數的約束,直接是在內存中拷貝的,構造函數是不會執行的。

應用場景:

  • 類初始化需要消化非常多的資源時
  • 性能和安全要求的場景,通過 new產生一個對象需要非常繁瑣的數據準備和訪問權限時;
  • 一個對象多個修改者的場景,一個對象需要提供給多個對象訪問,而且各個調用者都可以修改其值時;

注意地方:淺拷貝與深拷貝

Java的Object類提供的clone方法只是拷貝本對象,其對象內部的數組、引用對象等都不拷貝,其他的原始類型如int,char等都會被拷貝,拷貝后的對象與原生對象共享內部元素的地址(淺拷貝),如果拷貝后的對象修改了原生對象的數組,則原生對象也會看到修改。如果需要進行深拷貝,則需要在復寫的clone方法里對私有的類變量(內部數組,引用對象)進行獨立的拷貝。并且使用final關鍵字修飾的變量不能被拷貝;

中介者模式

優點:

  • 減少了類間的依賴,把原有的一對多的依賴變成了一對一的依賴;

    缺點:

  • 中介者會膨脹得很大,而且邏輯復雜;原本N個對象的依賴關系轉換為中介者與對象的依賴關系;

命令模式

優點:

  • 類間解耦,調用者與接收者之間沒有任何依賴關系,調用者實現功能時不需要了解到底是哪個接收者執行,只需調用Command抽象類的execute方法就可以了;
  • 可擴展性,Command的子類可以非常容易擴展,并且調用者和高層模塊不產生嚴重的代碼耦合;

缺點:

  • Command類膨脹厲害,如果有N個命令,則Command類的子類就為N個;

    應用場景:如Android中各種事件的處理;

責任鏈模式

優點:

  • 請求與處理分開,請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌;

缺點:

  • 性能問題,每個請求都是從鏈頭遍歷到鏈尾的,當這個責任鏈比較長時,遍歷開銷會比較大;

應用場景:

  • 如Android事件的傳遞機制;

裝飾器模式

優點:

  • 裝飾類和被裝飾類可以獨立發展,而不會互相耦合;
  • 裝飾模式是繼承關系的一個替代方案,不管裝飾多少層,最終返回的也還是那個對象;
  • 裝飾模式可以動態地擴展一個實現類的功能;

缺點:

  • 多層的裝飾比較復雜,當使用多層裝飾出現問題時,排查問題的工作量比較大

應用場景:

  • 需要擴展一個類的功能,或給一個類增加附加功能;
  • 需要為一批兄弟類進行改裝或加裝功能;

策略模式

優點:

  • 算法可以自由切換,只要實現抽象策略,它就成為策略家庭的一個成員;
  • 避免使用多重條件判斷,
  • 擴展性良好,在現有的系統中增加一個策略太容易,只要實現接口就可以了;

缺點:

  • 策略類數量多,每一個策略都是一個類,復用的可能性很小;
  • 所有的策略類都需要對外暴露,上層模塊必須知道有哪些策略,然后決定使用哪一個策略;

應用場景:

  • 多個類只有在算法或行為上稍有不同的場景;
  • 算法需要自由切換的場景;
  • 需要屏蔽算法規則的場景;

適配器模式

優點:

  • 讓兩個沒有任何聯系的類在一起運行;
  • 增加了類的透明性;
  • 提高了類的復用度;
  • 靈活性好,當不需要適配器時,只要刪掉這個適配器就可以了,

應用場景:

  • 修改一個已經投產的接口時,
  • Android中各種Adapter,

迭代器模式

  • 迭代器模式是為解決遍歷容器中的元素而誕生的,沒有人會單獨寫一個迭代器,使用Java提供的Itreator就可以滿足要求了;

組合模式

優點:

  • 高層模塊調用簡單,高層模塊不需要關心自己處理的是單個對象還是整個組合結構,
  • 節點可以自由增加;

缺點:

  • 調用時會直接使用實現類,不符合面向接口編程思想;

應用場景:

  • 維護和展示部分-整體關系的場景,如樹型菜單,文件和文件夾的管理;
  • 只要是樹型結構,就要考慮使用組合模式;

觀察者模式

優點:

  • 觀察者與被觀察者之間是抽象耦合,不管是增加觀察者還是被觀察者都非常容易擴展;
  • 建立一套觸發機制;

缺點:

  • 一個被觀察者,多個觀察者,開發與調度會比較復雜,在Java中消息的通知默認是順序執行,其中一個觀察者卡殼,會影響整體的執行效率,一般要考慮采用異步的方式;

應用場景:

  • 關聯行為場景,如Android中數據變化會引起UI的變化;
  • 事件多級觸發場景;
  • 跨系統的消息交換場景;

門面模式

優點:

  • 減少系統的相互依賴,所有的依賴都是與門面對象的依賴,與子系統無關。
  • 提高了靈活性;
  • 提高了安全性,想讓你訪問子系統的哪些業務就開通哪些邏輯;

缺點:

  • 不符合開閉原則,當出現bug后,只能通過修改門面角色的代碼來修復;

應用場景:

  • 為一個復雜的模塊或子系統提供一個供外界訪問的接口,如Android的Context類只是一個抽象類,所有的功能都是在ContextImpl類實現的,我們不會察覺到ContextImpl的存在,只需要調用Context就可以了;
  • 子系統相對獨立,外界對子系統的訪問只要黑箱操作即可;
  • 預防低水平開發人員帶來的風險,被限定在指定的子系統開發;

備忘錄模式

應用場景:

  • 需要保存和恢復數據的相關狀態場景;
  • 提供一個可回滾的操作場景;
  • 需要監控的副本場景中;
  • 數據庫連接的事務管理就是用的備忘錄模式;

注意事項:

  • 備忘錄的生命期,要主動管理它的生命周期,建立就要使用,不使用就刪除;
  • 備忘錄的性能,不要在頻繁建立備份的場景中使用備忘錄模式;(對象的創建是需要消耗資源的)

訪問者模式

優點:

  • 符合單一職責原則,具體元素角色負責數據的加載,而訪問者類則負責數據的呈現;
  • 優秀的擴展性,
  • 靈活性非常高;

缺點:

  • 具體元素對訪問者公布細節,訪問者要訪問一個類就必須要求這個類公布一些方法和數據;
  • 具體元素變更比較困難;具體元素角色的增加、刪除、修改都是比較困難;
  • 違背了依賴倒置原則,訪問者依賴的是具體的元素,而不是抽象的元素;

應用場景 :

  • 一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作;
  • 需要對一個對象結構中的對象進行很多不同并且不相關的操作,而你想避免讓這些操作”污染“這些對象的類;
  • 業務規則要求遍歷多個不同的對象;

狀態模式

優點:

  • 結構清晰,避免了過多的switch...caseif...else語句的使用;
  • 遵循設計原則,每個狀態就是一個子類;
  • 封裝性非常好,將狀態變換放置到類的內部來實現;

缺點:

  • 子類會太多,也就是類膨脹,有多少個狀態,就會有多少個子類;

    應用場景:

  • 行為隨狀態改變而改變的場景,如權限設計;
  • 條件、分支判斷語句的替代者,通過擴展子類實現條件的判斷處理;
  • 狀態的個數最好不要超過5個;

解釋器模式(現在使用較少)

優點:

  • 擴展性好,

缺點:

  • 解釋器模式會引起類膨脹;
  • 采用了遞歸調用方法;

享元模式

優點:

  • 大大減少應用程序創建的對象,降低程序內存的占用;

缺點:

  • 提高了系統復雜性,需要分離出內部和外部狀態;

應用場景:

  • 系統中存在大量的相似對象;
  • 需要緩沖池的場景;
  • 細粒度的對象都具有較接近的外部狀態;且內部狀態與環境無關

橋梁模式

優點:

  • 抽象與實現分離;
  • 優秀的擴充能力;
  • 實現細節對客戶透明;

應用場景:

  • 不希望或不適用繼承的場景;
  • 接口或抽象類不穩定的情況;
  • 重要性要求較高的場景;

轉載于:https://www.cnblogs.com/WoodJim/p/4715385.html

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

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

相關文章

How Many Shortest Path

zoj2760:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode2760 題意:給你一張有向帶權圖,然后問你最短路徑有多少條。 題解:這一題用到了網絡流,一開始,我想到用找到一條最短路,然后刪除這條…

pat00-自測5. Shuffling Machine (20)

00-自測5. Shuffling Machine (20) 時間限制400 ms內存限制65536 kB代碼長度限制8000 B判題程序Standard作者CHEN, YueShuffling is a procedure used to randomize a deck of playing cards. Because standard shuffling techniques are seen as weak, and in order to avoid …

E488: Trailing characters:

情景: 對vim進行配置,配置完成后進行保存,配置完成后打開其他文件時報錯。原因: vim 配置文件中保存不合乎語法的語句,報錯時如下: #顯示行號 set number#字符導致的錯誤,改成"即可。 vi…

移動web開發總結

1、-webkit-tap-highlight-color:rgba(255,255,255,0)可以同時屏蔽ios和android下點擊元素時出現的陰影。 備注:transparent的屬性值在android下無效。2、-webkit-appearance:none可以同時屏蔽輸入框怪異的內陰影。3,/*去除android瀏覽器下a/input等元素獲得焦點時高…

人物角色群體攻擊判定二(叉乘來判斷敵人的位置)

建議閱讀: 判斷敵人在玩家的某一個區域: http://www.cnblogs.com/plateFace/p/4716799.html 我們可以根據玩家和敵人的坐標, 進行叉乘來獲取一個向量可以用它來判斷敵人的位置, 敵人是否在攻擊范圍內. 下面我簡單實現下對單體敵人是否攻擊做判定 這種方式有一種重大的BUG, 假設…

更改linux子系統軟件源為國內鏡像

cd /etc/apt/sudo cp sources.list sources.list.back20190831sudo vim sources.list執行vim替換命令 :%s/archive.ubuntu/mirrors.aliyun/g:%s/security.ubuntu/mirrors.aliyun/g執行sudo apt update即可。

[Z] Linux下進程的文件訪問權限

原文鏈接:http://blog.csdn.net/chosen0ne/article/details/10581883對進程校驗文件訪問權限包括兩個部分,一是確定進程的角色(屬于哪個用戶或者組),二是確定對應的角色是否具有該操作的權限。 首先看第一部分。默認情…

HDU 5371 Manacher Hotaru's problem

求出一個連續子序列,這個子序列由三部分ABC構成,其中AB是回文串,A和C相同,也就是BC也是回文串。 求這樣一個最長的子序列。 Manacher算法是在所有兩個相鄰數字之間插入一個特殊的數字,比如-1, Manacher算法…

MySQL CURDATE() 函數

定義和用法 CURDATE() 函數返回當前的日期。 語法 CURDATE() 實例 例子 1 下面是 SELECT 語句: SELECT NOW(),CURDATE(),CURTIME() 結果類似: NOW()CURDATE()CURTIME()2008-12-29 16:25:462008-12-2916:25:46例子 2 下面的 SQL 創建帶有日期時間列 (Orde…

平庸技術流,用 WebApi +AngularJS 實現網絡爬蟲

最近園子里網絡爬蟲很火爆,從 PHP 到 Python,從 windows服務 到 winform 程序,各路大神各顯神通。小弟也獻下丑,從平庸流出發,簡述下 WebApi AngularJS 方式實現網絡爬蟲。 一、技術框架 1.1 前端: Angular…

linker `cc` not found

運行rustc hello_world.rs時出錯。原因: 我的 gcc 是安裝的指定版本 gcc-4.8,安裝指定版本 gcc 可參考我的另一篇博文,這里找不到 cc 的原因是在移除原來軟鏈的時候,cc 的軟鏈也移除了。重新建立軟鏈即可。 sudo ln -s gcc cc還有…

C# 通過服務啟動窗體(把窗體添加到服務里)實現用戶交互的windows服務[轉發]...

由于個人需要,想找一個鍵盤記錄的程序,從網上下載了很多,多數都是需要注冊的,另外也多被殺軟查殺。于是決定自己寫一個,如果作為一個windows應用程序,可以實現抓取鍵盤的記錄。想要實現隨系統啟動的話&…

error: default argument given for parameter 4

原因&#xff1a;定義函數的時候參數部分有默認值&#xff0c;如下&#xff1a; int classA::print(int a 0) {std::cout << a << std::endl; }分析&#xff1a;聲明函數時參數可以有默認值&#xff0c;定義時不能。

python2.7虛擬環境virtualenv安裝及使用

一 、虛擬環境virtualenv安裝 1. 安裝virtualenv 將Python的目錄添加到系統環境變量后&#xff0c;在命令行輸入&#xff1a; pip install virtualenv C:\Users\heroicai\Desktop>pip install virtualenv2. 建立虛擬環境 在桌面上建立建立一個虛擬環境myenv,輸入:virtualenv…

Io 異常: The Network Adapter could not establish the connection

Io 異常: The Network Adapter could not establish the connection 這個異常的出現一般與數據庫和你的PC的設置有關 這種異常的出現大致上有下面幾種&#xff1a; 1。IP錯誤。 在設置URL時錯誤&#xff0c;例如&#xff1a;jdbc:oracle:thin:192.168.0.36:1521:sharp 數據庫服…

git 刪除tag

git tag -d v1.0如果 tag 已經在遠程分支&#xff0c;還需執行一句git push origin :refs/tags/v1.0另&#xff1a;打 tag 的時候最好加上 description&#xff0c;防止出現未知的錯誤&#xff0c;如 Jenkins 集成的時候生成的包名不對等。

leetcode 的shell部分4道題整理

對shell的某些細節還不是十分熟悉&#xff0c;借鑒了好多別人的東西 1. Word Frequency此題很簡單&#xff0c;只要能排序就可以cat words.txt |tr -s " " "\n" sort | unique -c | sort -r | awk {print $2" "$1}2. Valid Phone Numbers cat …

Mysql操作集錦

mysql安裝成功后可以看到已經存在mysql、information_schema和test這個幾個數據庫&#xff0c;information_schema庫中有一個名為COLUMNS的表&#xff0c;這個表中記錄了數據庫中所有表的字段信息。知道這個表后&#xff0c;獲取任意表的字段就只需要一條select語句即可。 例如…

shadows a parameter

原因&#xff1a;函數內聲明變量與參數名相同。 如&#xff1a; void print(int hello) {int hello;std::cout << hello << std::endl; }解決辦法&#xff1a;改變參數參數名或者局部變量名

iOS 9之WatchKit for WatchOS 2

金田&#xff08;github示例源碼&#xff09; 自AppleWatch發行的同時就可以為AppWatch開發相應的應用程序&#xff0c;不過最初的版本&#xff0c;能開發的功能極為有限&#xff0c;所以也只是有少數的App廠商為Apple定制了App&#xff0c;所以迄今為止&#xff0c;Apple Stor…