設計模式簡要分析說明與歸納總結

来源:http://www.cnblogs.com/xiongzaiqiren/archive/2016/03/28/5328894.html
-Advertisement-
Play Games

* 軟體腐化的原因: 問題所在 設計目標 過於僵硬 可擴展性(新性能可以很容易加入系統)過於脆弱 靈活性(修改不會波及其它)復用率低 粘度過高 可插入性(新功能容易加入系統(氣囊加入方向盤)) * 提高系統可復用性的幾點原則:傳統復用:1. 代碼的粘帖復用2. 演算法的復用3. 數據結構的復用 * 可 ...


* 軟體腐化的原因:

問題所在 設計目標
----------------------------------------------------------------------------
過於僵硬 可擴展性(新性能可以很容易加入系統)
過於脆弱 靈活性(修改不會波及其它)
復用率低
粘度過高 可插入性(新功能容易加入系統(氣囊加入方向盤))

* 提高系統可復用性的幾點原則:
傳統復用:
1. 代碼的粘帖復用
2. 演算法的復用
3. 數據結構的復用

* 可維護性與可復用性並不完全一致

* 對可維護性的支持:


一、 "開放-封閉"原則(OCP)


Open-Closed Principle原則講的是:一個軟體實體應當對擴展開放,對修改關閉

優點:
  通過擴展已有軟體系統,可以提供新的行為,以滿足對軟體的新的需求,使變化中的軟體有一定的適應性和靈活性。
  已有軟體模塊,特別是最重要的抽象層模塊不能再修改,這使變化中的軟體系統有一定的穩定性和延續性。

 

例子:玉帝招安美猴王
當年大鬧天宮便是美猴王對玉帝的新挑戰。美猴王說:"'皇帝輪流做,明年到我家。'只教他搬出去,將天宮讓於我!"對於這項挑戰,太白金星給玉皇大帝提出的建議是:"降一道招安聖旨,宣上界來…,一則不勞師動眾,二則收仙有道也。"

換而言之,不勞師動眾、不破壞天規便是"閉",收仙有道便是"開"。招安之道便是玉帝天庭的"開放-封閉"原則。

招安之法的關鍵便是不允許更改現有的天庭秩序,但允許將妖猴納入現有秩序中,從而擴展了這一秩序。用面向對象的語言來講,不允許更改的是系統的抽象層,而允許更改的是系統的實現層。


二、 里氏代換原則(LSP)


Liskov Substitution Principle(里氏代換原則):子類型(subtype)必須能夠替換它們的基類型

白馬、黑馬

反過來的代換不成立
《墨子·小取》說:"娣,美人也,愛娣,非愛美人也……"娣便是妹妹,哥哥喜愛妹妹,是因為兩人是兄妹關係,而不是因為妹妹是個美人。因此,喜愛妹妹不等同於喜愛美人。用面向對象語言描述,美人是基類,妹妹是美人的子類。哥哥作為一個有"喜愛()"方法,接受妹妹作為參數。那麼,這個"喜愛()"方法一般不能接受美人的實例。

一個違反LSP的簡單例子(長方形和正方形)

public class Rectangle
{
   private long width;
   private long height;
    
   public void setWidth(long width)
   {
      this.width = width;
   }
   public long getWidth()
   {
      return this.width;
   }
   public void setHeight(long height)
   {
      this.height = height;
   }
   public long getHeight()
   {
      return this.height;
   }
}

public class Square
{
   private long side;
    
   public void setSide(long side)
   {
      this.side = side;
   }

   public long getSide()
   {
      return side;
   }
}

正方形不可以做長方形的子類

using System;

public class Rectangle
{
   private long width;
   private long height;
    
   public void setWidth(long width)
   {
      this.width = width;
   }
   public long getWidth()
   {
      return this.width;
   }
   public void setHeight(long height)
   {
      this.height = height;
   }
   public long getHeight()
   {
      return this.height;
   }
}

public class Square : Rectangle
{
   private long side;

   public void setWidth(long width)
   {
      setSide(width);
   }

   public long getWidth()
   {
      return getSide();
   }

   public void setHeight(long height)
   {
      setSide(height);
   }

   public long getHeight()
   {
      return getSide();
   }

   public long getSide()
   {
      return side;
   }

   public void setSide(long side)
   {
      this.side = side;
   }
}

public class SmartTest
{
   public void resize(Rectangle r)
   {
      while (r.getHeight() >= r.getWidth() )
      {
         r.setWidth(r.getWidth() + 1);
      }
   }
}

在執行SmartTest的resize方法時,如果傳入的是長方形對象,當高度大於寬度時,會自動增加寬度直到超出高度。但是如果傳入的是正方形對象,則會陷入死迴圈。

代碼重構

public interface Quadrangle
{
   public long getWidth();
   public long getHeight();
}

public class Rectangle : Quadrangle 
{
   private long width;
   private long height;
    
   public void setWidth(long width)
   {
      this.width = width;
   }
   public long getWidth()
   {
      return this.width;
   }
   public void setHeight(long height)
   {
      this.height = height;
   }
   public long getHeight()
   {
      return this.height;
   }
}

public class Square : Quadrangle 
{
   private long side;

   public void setSide(long side)
   {
      this.side = side;
   }

   public long getSide()
   {
      return side;
   }

   public long getWidth()
   {
      return getSide();
   }

   public long getHeight()
   {
      return getSide();
   }
}

三、 依賴倒置原則(DIP)

依賴倒置(Dependence Inversion Principle)原則講的是:要依賴於抽象,不要依賴於具體

簡單的說,依賴倒置原則要求客戶端依賴於抽象耦合。原則表述:

  1,抽象不應當依賴於細節;細節應當依賴於抽象;
  2,要針對介面編程,不針對實現編程。

反面例子:

缺點:耦合太緊密,Light發生變化將影響ToggleSwitch。

解決辦法一:
將Light作成Abstract,然後具體類繼承自Light。

優點:ToggleSwitch依賴於抽象類Light,具有更高的穩定性,而BulbLight與TubeLight繼承自Light,可以根據"開放-封閉"原則進行擴展。只要Light不發生變化,BulbLight與TubeLight的變化就不會波及ToggleSwitch。

缺點:如果用ToggleSwitch控制一臺電視就很困難了。總不能讓TV繼承自Light吧。

解決方法二:

優點:更為通用、更為穩定。

結論:
使用傳統過程化程式設計所創建的依賴關係,策略依賴於細節,這是糟糕的,因為策略受到細節改變的影響。依賴倒置原則使細節和策略都依賴於抽象,抽象的穩定性決定了系統的穩定性。

四、 介面隔離原則(ISP)

介面隔離原則(Interface Segregation Principle)講的是:使用多個專門的介面比使用單一的總介面總要好。換而言之,從一個客戶類的角度來講:一個類對另外一個類的依賴性應當是建立在最小介面上的

過於臃腫的介面是對介面的污染。不應該強迫客戶依賴於它們不用的方法。

My object-oriented umbrella(摘自Design Patterns Explained)

Let me tell you about my great umbrella. It is large enough to get into! In fact, three or four other people can get in it with me. While we are in it, staying out of the rain, I can move it from one place to another. It has a stereo system to keep me entertained while I stay dry. Amazingly enough, it can also condition the air to make it warmer or colder. It is one cool umbrella.

My umbrella is convenient. It sits there waiting for me. It has wheels on it so that I do not have to carry it around. I don't even have to push it because it can propel itself. Sometimes, I will open the top of my umbrella to let in the sun. (Why I am using my umbrella when it is sunny outside is beyond me!)

In Seattle, there are hundreds of thousands of these umbrellas in all kinds of colors. Most people call them cars.

實現方法:

  1、 使用委托分離介面
  2、 使用多重繼承分離介面

五、 合成/聚合復用原則(CARP)

合成/聚合復用原則(Composite/Aggregate Reuse Principle或CARP)經常又叫做合成復用原則(Composite Reuse Principle或CRP),就是在一個新的對象裡面使用一些已有的對象,使之成為新對象的一部分;新對象通過向這些對象的委派達到復用已有功能的目的

簡而言之,要儘量使用合成/聚合,儘量不要使用繼承。

o Design to interfaces.
o Favor composition over inheritance.
o Find what varies and encapsulate it.
(摘自:Design Patterns Explained)

區分"Has-A"與"Is-A"

"Is-A"是嚴格的分類學意義上定義,意思是一個類是另一個類的"一種"。而"Has-A"則不同,它表示某一個角色具有某一項責任。

導致錯誤的使用繼承而不是合成/聚合的一個常見的原因是錯誤的把"Has-A"當作"Is-A"。

例如:

實際上,雇員、經理、學生描述的是一種角色,比如一個人是"經理"必然是"雇員",另外一個人可能是"學生雇員",在上面的設計中,一個人無法同時擁有多個角色,是"雇員"就不能再是"學生"了,這顯然是不合理的。

錯誤源於把"角色"的等級結構與"人"的等級結構混淆起來,誤把"Has-A"當作"Is-A"。解決辦法:

六、 迪米特法則(LoD)

迪米特法則(Law of Demeter或簡寫LoD)又叫最少知識原則(Least Knowledge Principle或簡寫為LKP),也就是說,一個對象應當對其它對象有儘可能少的瞭解

其它表述:
只與你直接的朋友們通信
不要跟"陌生人"說話
每一個軟體單位對其它的單位都只有最少的知識,而且局限於那些與本單位密切相關的軟體單位。

迪米特法則與設計模式
Facade模式、Mediator模式

使民無知
《老子》第三章曰:"是以聖人之治,虛其心,實其腹,弱其志,常使民無知無欲。"使被"統治"的對象"愚昧"化,處於"無知"的狀態,可以使"統治"的成本降低。
所謂"最少知識"原則,實際上便是老子的"使民無知"的統治之術。

不相往來
《老子》雲:"小國寡民……鄰國相望,雞犬之聲相聞,民至老死,不相往來。"將被統治的對象隔離開來,使它們沒有直接的通信,可以達到分化瓦解,繼而分而治之的效果。迪米特法則與老子的"小國寡民"的統治之術不謀而合。

 

 

參考文獻:
閻巨集,《Java與模式》,電子工業出版社
[美]James W. Cooper,《C#設計模式》,電子工業出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中國電力出版社
[美]Robert C. Martin,《敏捷軟體開發-原則、模式與實踐》,清華大學出版社
[美]Don Box, Chris Sells,《.NET本質論 第1捲:公共語言運行庫》,中國電力出版社
http://www.dofactory.com/Patterns/Patterns.aspx

 

以上內容摘抄自:http://www.cnblogs.com/zhenyulu/articles/36061.html


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

-Advertisement-
Play Games
更多相關文章
  • C是結構化和模塊化的語言,是基於過程的。 C++是面向對象的程式設計語言。 C++是C的超集,對C的功能做了擴充,增加了面向對象的機制。 C++包含頭文件的時候只寫文件名,不加“.h”。 使用C++標準庫中的類或函數的時候,要用“using namespace std”作聲明,因為C++標準庫中的類 ...
  • 我個人比較喜歡寫註釋,在工作中對註釋的重要性看的也比較高,所以大部分文字都在註釋中,代碼外的文字會寫的偏少,關鍵能懂就行 先看一下整合後的工程目錄(單工程,多工程以後會採用maven) 5個package分別對應 action, entity, mapper(也就是DAO,採用動態代理), serv ...
  • 課程總共包含100個課時,總授課長達27多個小時,內容覆蓋面廣,從入門到精通,授課通俗易懂,分析問題獨到精辟通過本套視頻的學習,學員能夠快速的掌握java編程語言,成為java高手。課程目錄:課時1 01lesson1 Java概述 17:18課時2 02lesson1 Java跨平臺的原理 11: ...
  • 教程簡介 本教程由後盾網講解,共40節,主要介紹了美團網的開發,從需求分析出發,對商鋪的建立、購物流程的構建及訂單處理等都做了詳細的介紹,非常適合做電子商務開發的朋友和同學參考學習使用,完整教程可以在本站下載觀看,同時提供部分章節線上觀看,完整目錄如下: 1.項目介紹,流程分析以及表關係建立2.後臺 ...
  • 後盾網教程統一大集合整理(內容較多,請自備紙巾) 傳送門:http://fu83.cn/thread-162-1-1.html ...
  • 什麼叫架構?揭開架構神秘的面紗,無非就是:分層+模塊化。任意複雜的架構,你也會發現架構師也就做了這兩件事。 本文將會全面的介紹我們團隊在模塊化設計方面取得的經驗。之所以加了“全面”二字,是因為本文的內容將會涉及到:資料庫、路由、C#、JavaScript、CSS、HTML等一個完整模塊所需要的內容。 ...
  • 序言 在.Net的世界中,一提及SOA,大家想到的應該是Web Service,WCF,還有人或許也會在.NET MVC中的Web API上做上標記,然後泛泛其談! 的確,微軟的這些技術也確實推動著面向服務的世界發展,當然除了微軟還有很多面向服務的開源技術,甚至在某些方面比微軟做的更加優秀。那麼什麼 ...
  • 一、前言 面向對象技術可以很好地解決一些靈活性或可擴展性問題,但在很多情況下需要在系統中增加類和對象的個數。當對象數量太多時,將導致運行代價過高,帶來性能下降等問題。 享元模式正是為解決這一類問題而誕生的。享元模式通過共用技術實現相同或相似對象的重用。 在享元模式中通常會出現工廠模式,需要創建一個享 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...