再讀設計模式七原則

来源:http://www.cnblogs.com/XiongMaoMengNan/archive/2017/09/25/7592702.html
-Advertisement-
Play Games

GOF《設計模式》一書中提出了七條設計原則,七原則是一種理想狀態的表達,但實際項目開發中可能會不得不打破這些原則的限制。任何基類可以出現的地方,子類一定可以出現,且必須遵從基類所有規則定義,但反過來說,除了擴展基類,我們又為什麼要違背基類規則定義呢?這一條與開關原則結合起來理解就是,基類遵循關原則,... ...


GOF《設計模式》一書中提出了七條設計原則,七原則是一種理想狀態的表達,但實際項目開發中可能會不得不打破這些原則的限制。

1. 單一職責原則(Single Responsibility Principle, SRP): There should never be more than one reason for a class to change. 言下之意做到類只承擔單一職責(最細粒度)也就能儘可能地降低類變更的可能性,不同職責要分開單獨定義。其實這一原則不僅僅適用於類,還適用於介面以及方法的設計;

2. 開閉原則(Open-Closed Principle, OCP): Softeware entities like classes,modules and functions should be open for extension but closed for modifications. 這句話翻譯過來大意就是,一個軟體實體如類、模塊和函數,應該通過擴展來實現變化,而不是通過修改已有代碼來實現變化。比如參數類型、引用對象儘量使用介面或者抽象類,而不是具體實現類;

3. 依賴倒轉原則(Dependence Inversion Principle, DIP): High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. 依賴多出現在方法參數中。高層模塊不應該依賴低層模塊(具體實現),以防止一旦低層模塊(具體實現)發生變化,將引起高層模塊不必要的改變,同時高層模塊之上可能有更高層的模塊存在,因此兩者都應該依賴於抽象。抽象不依賴具體實現細節,而讓具體實現細節依賴抽象。抽象不變,具體實現細節改變可以使影響最小化,也就是要針對介面編程。這一條與里氏代換原則結合起來更容易理解,也可以看出這些原則並不應該被孤立地運用於系統設計中,而應該協同配合起來運用;

4. 里氏代換原則(Liskov Substitution Principle, LSP): Functions that use pointers or referrnces to base classes must be able to use objects of derived classes without knowing it. 任何基類可以出現的地方,子類一定可以出現,且必須遵從基類所有規則定義,但反過來說,除了擴展基類,我們又為什麼要違背基類規則定義呢?這一條與開關原則結合起來理解就是,基類遵循關原則,子類遵循開原則,子類必須滿足LSP才允許繼承,否則就斷開這種繼承關係;

5. 介面隔離原則(Interface Segregation Principle, ISP): Clients should not be forced to depend upon interfaces that they don't use.The dependcy of one class to another one should depend on the smallest possible interface. 使用多個隔離的介面,比使用單個介面要好,也有利於降低類之間的耦合度。類間的依賴關係要建立在最小的介面之上,要防止類必須實現介面中對於自己來說無用的方法情形的出現;

6. 迪米特法則(Law of Demeter, LoD),也稱最少知識原則(Least Knowledge Principle, LKP): Only talk to your immedate friends. 一個模塊或子系統應當儘量少地與其他模塊或子系統之間發生直接相互作用,可以通過增加“即時朋友”這個中間人來中轉通信,只與“朋友”保持聯繫,與“陌生人”概不謀面,當模塊或子系統出現版本升級更新或環境移植之後,只要朋友不變就好;

7. 合成/聚合復用原則(Composite/Aggregate ReusePrinciple ,CARP):該原則要求在設計上儘量使用合成/聚合來達到復用的目的,而不是使用繼承,也就是說前者優先於後者而被運用。繼承會將基類的細節暴露給子類,也稱白箱復用,如果基類發生改變,子類也必須相應做出變動,且多繼承不易維護。CARP幾乎可用於任何環境,依賴少,但是合成/聚合造成類中多對象需要管理。下邊是CARP運用的一個實例:

/**
* 合成
*/
class Person
{
    private $hand;
    
    public function Person()
    {
        $hand = New Hand();
    }
}

/**
* 聚合
*/
class Person
{
    private $hand;
    
    public function setHand()
    {
        $this->hand = New Hand();
    }
}

下邊是一段用來表達上述某些設計原則精神的代碼(PHP):

<?php
/**
* 下列代碼只用於表達《設計模式》中的某些設計原則精神。
* 如果是場景中會多次重覆創建同一計算器,可以考慮單例模式或靜態調用。
*/


/**
*
* Calculation介面對add、sub、mul和div等二元運算類型進行了簡單的抽象定義。
*
* 要執行新的計算類型,只需在新的計算器類中實現該介面即可,不必修改任何已有代碼。
*
*/
interface Calculation
{    
    /**
    * do()方法可擴展到其他二元運算類型
    *
    *
    */
    public function do(float $operand1, float $operand2) : float;
}

/**
* AddCalculator 加法運算器
*/
class AddCalculator implements Calculation
{
    /**
    * 執行加法運算
    */
    public function do(float $operand1, float $operand2) : float
    {
        return $operand1 + $operand2;
    }
}

/**
* SubCalculator 減法運算器
*/
class SubCalculator implements Calculation
{
    /**
    * 執行減法運算
    */
    public function do(float $operand1, float $operand2) : float
    {
        return $operand1 - $operand2;
    }
}

/**
* MulCalculator 乘法運算器
*/
class MulCalculator implements Calculation
{
    /**
    * 執行乘法運算
    */
    public function do(float $operand1, float $operand2) : float
    {
        return $operand1 * $operand2;
    }
}

/**
* DivCalculator 除法運算器
*/
class DivCalculator implements Calculation
{
    /**
    * 執行除法運算
    */
    public function do(float $operand1, float $operand2) : float
    {
        return $operand1 / $operand2;
    }
}


class Calculator
{ 
    /**
    * 當前計算器
    */
    private $calculator;
    
    /**
    * 用於保存當前運算結果,可用作下一次運算的 $operand1
    */
    private $result = NULL;
    
    public function __construct(Calculation $calculator = NULL)
    {
        $this->calculator = $calculator;
    }
    
    /**
    * 更換當前計算器
    *
    * @return void
    */
    public function renewCalculator(Calculation $calculator)
    {
        $this->calculator = $calculator;
    }
    
    /**
    * 執行計算
    */
    public function do(float $operand1, float $operand2 = NULL, Calculation $calculator = NULL) : float
    {
        //如果$calculator != NULL,則更換當前計算器
        $this->calculator = $calculator ?? $this->calculator;
        
        if ($operand2 === NULL) {//啟用前一次運算結果
            $operand2 = $operand1;
            $operand1 = $this->result;
        }
        
        $this->result = $this->calculator->do($operand1, $operand2);
        echo "{$this->result}\n";
        
        return $this->result;
    }
}

$cal = new Calculator(new AddCalculator());
$cal->do(12, 104.5);//116.5
$cal->do(12);//128.5

$cal->renewCalculator(new SubCalculator());
$cal->do(12);//116.5
$cal->do(104.5);//12
$cal->do(12);//0
$cal->do(12, null, new AddCalculator());//12

$cal->renewCalculator(new MulCalculator());
$cal->do(12, 104.5);//1254
$cal->do(12);//15048

$cal->renewCalculator(new DivCalculator());
$cal->do(12);//1254
$cal->do(12);//104.5
$cal->do(0);//INF. Warning: Division by zero
$cal->do(INF);//NAN
$cal->do('INF');//Fatal error: Uncaught TypeError: Argument 1 passed to Calculator::do() must be of the type float, string given

 


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

-Advertisement-
Play Games
更多相關文章
  • 1.什麼是servlet轉發? servlet將用戶的請求通過一組servlet來處理,每個servlet都有自己特定的職責,當該servlet完成自己的工作後將請求轉發到下一個servlet來處理,這種通過不同servelet相互轉發請求來完成對某個請求的處理過程就叫做servlet轉發。 2.什 ...
  • 本節內容 1.交互操作 2.變數 3.字元串 4.for迴圈、while迴圈 5.break語句、continue語句 1.交互操作 在cmd下的 開始--》cmd--》cd c:\ --》dir cd d:\=切換到d盤 cd=change directory dir=查看當前路徑下的文件 文件名 ...
  • 靜態代碼塊:最早執行, 類 被載入記憶體時執行,只執行一次。沒有名字、參數和返回值,有關鍵字static。 構造代碼塊:執行時間比靜態代碼塊晚,比構造函數早,和構造函數一樣,只在 對象 初始化的時候運行。沒有名字、參數和返回值。 構造函數:執行時間比構造代碼塊時間晚,也是在 對象 初始化的時候運行。沒 ...
  • 初學者先廣在精,關註代碼背後的實現,關註內功修煉,瞭解實現原理和思想,形成自己完整的技術體系,知識成片之後就容易觸類旁通,進步的速度就會越來越快。最後以我在每一個項目組和開發人員聊天都會說的幾個例子結尾:“少林功夫裡面有功和拳之分,馬步功,石鎖功是功,蛇拳猴拳是拳,你不可能練會了蛇拳猴拳就能打人,你... ...
  • 簡單工廠模式 工廠模式 抽象工廠模式 簡單工廠模式 工廠模式 抽象工廠模式 簡單工廠模式 什麼是簡單工廠模式? 在現實生活中工廠是負責生產產品的,同樣在設計模式中,簡單工廠模式我們也可以理解為負責生產對象的一個類, 我們平常編程中,當使用"new"關鍵字創建一個對象時,此時該類就依賴與這個對象,也就 ...
  • 微服務里一個重要的概念就是服務註冊與發現技術,當你有一個新的服務運行後,我們的服務中心可以感知你,然後把加添加到服務列表裡,然後當你死掉後,會從服務中心把你移除,而你作為一個服務,對其它服務公開的只是服務名稱,而不是最終的服務地址URL,這對於雲平臺,容器化架構來說是非常重要的! 一 安裝單獨的Eu ...
  • 1.類圖 UML類圖是用來描述類、介面、協作及它們之間的關係的圖。用來顯示系統中各個類的靜態結構。 2.類圖的組成元素 類圖由以下六種元素組成:類,介面,泛化關係,關聯關係,依賴關係,實現關係。 3.類圖的繪製 3.1類圖的表示法 類的UML表示為一個長方形垂直分為三個部分:頂部為類的名稱部分,中間 ...
  • Redis是一個key value存儲系統,現在在各種系統中的使用越來越多,大部分情況下是因為其高性能的特性,被當做緩存使用,這裡介紹下Redis經常遇到的使用場景。 Redis特性 一個產品的使用場景肯定是需要根據產品的特性,先列舉一下Redis的特點: 讀寫性能優異 持久化 數據類型豐富 單線程 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...