1. 程式人生 > >設計模式原則詳解

設計模式原則詳解

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

      我們在應用程式開發中,一般要求儘量兩做到可維護性和可複用性。
       應用程式的複用可以提高應用程式的開發效率和質量,節約開發成本,恰當的複用還可以改善系統的可維護性。而在面向物件的設計裡面,

可維護性複用都是以面向物件設計原則為基礎的,這些設計原則首先都是複用的原則,遵循這些設計原則可以有效地提高系統的複用性,同時提高系統的可維護性。 面向物件設計原則和設計模式也是對系統進行合理重構的指導方針。

      常用的面向物件設計原則包括7個,這些原則並不是孤立存在的,它們相互依賴,相互補充。

       

1.單一職責原則(Single Responsibility Principle,SRP):類的職責要單一,不能將太多的職責放在一個類中。(高內聚、低耦合)

定義:一個物件應該只包含單一的職責,並且該職責被完整地封裝在一個類中。(Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.),即又定義有且僅有一個原因使類變更。

原則分析: 1)一個類(或者大到模組,小到方法)承擔的職責越多,它被複用的可能性越小,而且如果一個類承擔的職責過多,就相當於將這些職責耦合在一起,當其中一個職責變化時,可能會影響其他職責的運作。 
2)類的職責主要包括兩個方面:資料職責和行為職責,資料職責通過其屬性來體現,而行為職責通過其方法來體現。
3)單一職責原則是
實現高內聚、低耦合的 指導方針,在很多程式碼重構手法中都能找到它的存在,它是最簡單但又最難運用的原則,需要設計人員發現類的不同職責並將其分離,而發現類的多重職責需要設計人員具有較強的分析設計能力和相關重構經驗。  例子:
最簡單例子是:一個數據結構職責類和演算法行為都放在一個類User。我們應該把資料結構和行為分開。現使用單一職責原則對User類進行重構。 優點:
1、降低類的複雜性,類的職責清晰明確。比如資料職責和行為職責清晰明確。
2、提高類的可讀性和維護性,
4、變更引起的風險減低,變更是必不可少的,如果介面的單一職責做得好,一個介面修改只對相應的類有影響,對其他介面無影響,這對系統的擴充套件性、維護性都有非常大的幫助。
注意:單一職責原則提出了一個編寫程式的標準,用“職責”或“變化原因”來衡量介面或類設計得是否合理,但是“職責”和“變化原因”都是沒有具體標準的,一個類到底要負責那些職責?這些職責怎麼細化?細化後是否都要有一個介面或類?這些都需從實際的情況考慮。因專案而異,因環境而異。

2.原則Open - ClosedPrinciple ,OCP ):對擴充套件開放,對修改關閉(設計模式的核心原則是

 定義:一個軟體實體(如類、模組和函式)應該對擴充套件開放,對修改關閉.  意思是,在一個系統或者模組中,對於擴充套件是開放的,對於修改是關閉的,一個 好的系統是在不修改原始碼的情況下,可以擴充套件你的功能. 而實現開閉原則的關鍵就是抽象化.

原則分析 :

1)當軟體實體因需求要變化時, 儘量通過擴充套件已有軟體實體,可以提供新的行為,以滿足對軟體的新的需求,而不是修改已有的程式碼,使變化中的軟體有一定的適應性和靈活性 。已有軟體模組,特別是最重要的抽象層模組不能再修改,這使變化中的軟體系統有一定的穩定性和延續性。

2)實現開閉原則的關鍵就是抽象化 :在"開-閉"原則中,不允許修改的是抽象的類或者介面,允許擴充套件的是具體的實現類,抽象類和介面在"開-閉"原則中扮演著極其重要的角色..即要預知可能變化的需求.又預見所有可能已知的擴充套件..所以在這裡"抽象化"是關鍵!

3)可變性的封閉原則:找到系統的可變因素,將它封裝起來這是對"開-閉"原則最好的實現. 不要把你的可變因素放在多個類中,或者散落在程式的各個角落. 你應該將可變的因素,封套起來..並且切忌不要把所用的可變因素封套在一起. 最好的解決辦法是,分塊封套你的可變因素!避免超大類,超長類,超長方法的出現!!給你的程式增加藝術氣息,將程式藝術化是我們的目標!

例子:我們前面提到的模板方法模式和觀察者模式都是開閉原則的極好體現。


3.里氏代換原則Liskov Substitution Principle ,LSP ):任何基類可以出現的地方,子類也可以出現

定義:第一種定義方式相對嚴格:如果對每一個型別為S的物件o1,都有型別為T的物件o2,使得以T定義的所有程式P在所有的物件o1都代換成o2時,程式P的行為沒有變化,那麼型別S是型別T的子型別。

第二種更容易理解的定義方式: 所有引用基類(父類)的地方必須能透明地使用其子類的物件。即 子類能夠必須能夠替換基類能夠從出現的地方。子類也能在基類 的基礎上新增行為。 里氏代換原則由 2008 年圖靈獎得主、美國第一位電腦科學女博士、麻省理工學院教授 Barbara Liskov 和卡內基 . 梅隆大學 Jeannette Wing 教授於 1994 年提出。其原文如下: Let q(x) be a property provableabout objects x of type T. Then q(y) should be true for objects y of type Swhere S is a subtype of T.   ) 原則分析: 1)講的是基類和子類的關係,只有這種關係存在時,里氏代換原則才存在。正方形是長方形是理解里氏代換原則的經典例子。 2)里氏代換原則可以通俗表述為:在 軟體中如果能夠使用基類物件,那麼一定能夠使用其子類物件 。把基類都替換成它的子類,程式將不會產生任何錯誤和異常,反過來則不成立,如果一個軟體實體使用的是一個子類的話,那麼它不一定能夠使用基類。 3) 里氏代換原則是實現開閉原則的重要方式之一,由於使用基類物件的地方都可以使用子類物件,因此 在程式中儘量使用基類型別來對物件進行定義,而在執行時再確定其子類型別,用子類物件來替換父類物件
例子:正方形不是長方形 在數學領域裡,正方形毫無疑問是長方形,它是一個長寬相等的長方形。所以,我們開發的一個與幾何圖形相關的軟體系統中,讓正方形繼承自長方形是順利成章的事情。由於正方形的度和寬度必須相等,所以在方法setLengthsetWidth中,對長度和寬度賦值相同。
/** * 長方形類Rectangle: * */class Rectangle double length;  double width;  public double getLength() { return length; }   public void setLength(double height) { this.length = length; }     public double getWidth() { return width; }  public void setWidth(double width) { this.width = width; } }

正方形整合長方形:
/** * 正方形類Square: */class Square extends Rectangle public void setWidth(double width) {    super.setLength(width);    super.setWidth(width);    }  public void setLength(double length) {     super.setLength(length);    super.setWidth(length);     } }

     由於正方形的度和寬度必須相等,所以在方法setLengthsetWidth中,對長度和寬度賦值相同。類TestRectangle是我們的軟體系統中的一個元件,它有一個resize方法要用到基類Rectangleresize方法的功能是模擬長方形寬度逐步增長的效果 :
  
測試類TestRectangle

class TestRectangle public void resize(Rectangle objRect) {    while(objRect.getWidth() <= objRect.getLength()  ) {        objRect.setWidth(  objRect.getWidth () + 1 );    }  }}
     我們執行一下這段程式碼就會發現,假如我們把一個普通長方形作為引數傳入resize方法,就會看到長方形寬度逐漸增長的效果,當寬度大於長度,程式碼就會停止,這種行為的結果符合我們的預期;假如我們再把一個正方形作為引數傳入resize方法後,就會看到正方形的寬度和長度都在不斷增長,程式碼會一直執行下去,直至系統產生溢位錯誤。所以,普通的長方形是適合這段程式碼的,正方形不適合。
    
我們得出結論:在resize方法中,Rectangle型別的引數是不能被Square型別的引數所代替,如果進行了替換就得不到預期結果。因此,Square類和Rectangle類之間的繼承關係違反了里氏代換原則,它們之間的繼承關係不成立,正方形不是長方形。
優缺點: 在面向物件的語言中,繼承是必不可少的、非常優秀的語言機制,它有如下優點: 1)程式碼共享,減少建立類的工作量,每個子類都擁有父類的方法和屬性; 2)提高程式碼的重用性;
3)子類可以形似父類,但又異於父類,“龍生龍,鳳生鳳,老鼠生來會打洞”是說子擁有父的“種”,“世界上沒有兩片完全相同的葉子”是指明子與父的不同;
4)提高程式碼的可擴充套件性,實現父類的方法就可以“為所欲為”了,君不見很多開源框架的擴充套件介面都是通過繼承父類來完成的;
5)提高產品或專案的開放性。
 
自然界的所有事物都是優點和缺點並存的,即使是雞蛋,有時候也能挑出骨頭來,繼承的缺點如下:
1)繼承是侵入性的。只要繼承,就必須擁有父類的所有屬性和方法;
2)降低程式碼的靈活性。子類必須擁有父類的屬性和方法,讓子類自由的世界中多了些約束;
3)增強了耦合性。當父類的常量、變數和方法被修改時,必需要考慮子類的修改,而且在缺乏規範的環境下,這種修改可能帶來非常糟糕的結果——大片的程式碼需要重構。


4.依賴倒轉原則Dependence Inversion Principle ,DIP ):要依賴抽象,而不要依賴具體的實現.

定義:高層模組不應該依賴低層模組,它們都應該依賴抽象抽象不應該依賴於細節,細節應該依賴於抽象。簡單的說,依賴倒置原則要求客戶端依賴於抽象耦合。原則表述:

1)抽象不應當依賴於細節;細節應當依賴於抽象;

2)要針對介面程式設計,不針對實現程式設計。

原則分析:

1)如果說開閉原則是面向物件設計的目標,依賴倒轉原則是到達面向設計"開閉"原則的手段..如果要達到最好的"開閉"原則,就要儘量的遵守依賴倒轉原則. 可以說依賴倒轉原則是對"抽象化"的最好規範! 我個人感覺,依賴倒轉原則也是里氏代換原則的補充..你理解了里氏代換原則,再來理解依賴倒轉原則應該是很容易的。

2)依賴倒轉原則的常用實現方式之一是在程式碼中使用抽象類,而將具體類放在配置檔案中。 

3) 類之間的耦合: 零耦合 關係, 具體耦合 關係, 抽象耦合 關係。 依賴倒轉原則要求客戶端依賴於抽象耦合 ,以抽象方式耦合是依賴倒轉原則的關鍵。
理解這個依賴倒置,首先我們需要明白依賴在面向物件設計的概念: 依賴關係(Dependency): 是一種 使用關係 ,特定事物的改變有可能會影響到使用該事物的其他事物,在需要表示一個事物使用另一個事物時使用依賴關係。( 假設 A 類的變化引起了 B 類的變化,則說名 B 類依賴於 A 類。 )大多數情況下, 依賴關係體現在某個類的方法使用另一個類的物件作為引數 在UML中,依賴關係用帶箭頭的虛線表示, 由依賴的一方指向被依賴的一方。

例子:某系統提供一個數據轉換模組,可以將來自不同資料來源的資料轉換成多種格式,如可以轉換來自資料庫的資料(DatabaseSource)、也可以轉換來自文字檔案的資料(TextSource),轉換後的格式可以是XML檔案(XMLTransformer)、也可以是XLS檔案(XLSTransformer)等。

由於需求的變化,該系統可能需要增加新的資料來源或者新的檔案格式,每增加一個新的型別的資料來源或者新的型別的檔案格式,客戶類 MainClass 都需要修改原始碼,以便使用新的類,但違背了開閉原則。現使用依賴倒轉原則對其進行重構。 
[java] view plain copy print ?
  1. <code class="language-java">/** 
  2.  * 抽象介面 
  3.  * @author mo-87 
  4.  * 
  5.  */  
  6. abstract public class AbstractSource {  
  7.     abstract public  void getSource();  
  8. }  
  9. /** 
  10.  * 抽象介面 
  11.  * @author mo-87 
  12.  * 
  13.  */  
  14. abstract public  class AbstractStransformer {  
  15.     abstract public  void transform();  
  16. }  
  17. /** 
  18.  * 具體實現 
  19.  * @author mo-87 
  20.  * 
  21.  */  
  22. public class DatabaseSource extends AbstractSource{  
  23.       
  24.     public  void getSource(){  
  25.          System.out.println("Get source data");    
  26.     }  
  27. }  
  28.   
  29. /** 
  30.  * 依賴注入是依賴AbstractSource抽象注入的,而不是具體 
  31.  * DatabaseSource 
  32.  *  
  33.  * @author mo-87 
  34.  * 
  35.  */  
  36. public class XMLStransformer {  
  37.     /** 
  38.      *  
  39.      */  
  40.     private AbstractSource source;   
  41.     /** 
  42.      * 構造注入(Constructor Injection):通過建構函式注入例項變數。 
  43.      */  
  44.     public void XMLStransformer(AbstractSource source){  
  45.         this.source = source;           
  46.     }  
  47.                          
  48.     /**      
  49.      * 設值注入(Setter Injection):通過Setter方法注入例項變數。 
  50.      * @param source : the sourceto set        
  51.      */       
  52.     public void setSource(AbstractSource source) {            
  53.         this.source = source;             
  54.     }  
  55.     /** 
  56.      * 介面注入(Interface Injection):通過介面方法注入例項變數。 
  57.      * @param source 
  58.      */  
  59.     public void transform(AbstractSource source ) {    
  60.         source.getSource();  
  61.         System.out.println("Stransforming ...");    
  62.     }      
  63. }</code>  
/** * 抽象介面 * @author mo-87 * */abstract public class AbstractSource abstract public  void getSource();}/** * 抽象介面 * @author mo-87 * */abstract public  class AbstractStransformer abstract public  void transform();}/** * 具體實現 * @author mo-87 * */public class DatabaseSource extends AbstractSource{     public  void getSource(){   System.out.println("Get source data");   }}/** * 依賴注入是依賴AbstractSource抽象注入的,而不是具體 * DatabaseSource *  * @author mo-87 * */public class XMLStransformer {    /**     *      */ private AbstractSource source;  /**  * 構造注入(Constructor Injection):通過建構函式注入例項變數。  */ public void XMLStransformer(AbstractSource source){  this.source = source;          }                     /**       * 設值注入(Setter Injection):通過Setter方法注入例項變數。  * @param source : the sourceto set         */      public void setSource(AbstractSource source) {            this.source = source;            } /**  * 介面注入(Interface Injection):通過介面方法注入例項變數。  * @param source  */ public void transform(AbstractSource source ) {    source.getSource();  System.out.println("Stransforming ...");   }    }

     

     

    
    
     依賴注入的三種寫法:
    
    
     
      
      
       
       構造注入
       (Constructor Injection)
       :通過
       建構函式
       注入例項變數。
      
      
       
       設值注入
       (Setter Injection)
       :通過
       Setter
       方法
       注入例項變數。
      
      
       介面注入(Interface Injection):通過
       介面方法注入例項變數。
      
      
       
public class XMLStransformer {     /**      *       */ private AbstractSource source;  /**  * 構造注入(Constructor Injection):通過建構函式注入例項變數。  */ public void XMLStransformer(AbstractSource source){  this.source = source;          }                     /**       * 設值注入(Setter Injection):通過Setter方法注入例項變數。  * @param source : the sourceto set         */      public void setSource(AbstractSource source) {            this.source = source;            } /**  * 介面注入(Interface Injection):通過介面方法注入例項變數。  * @param source  */ public void transform(AbstractSource source ) {    source.getSource();  System.out.println("Stransforming ...");   }    }

優點:採用依賴倒置原則可以減少類間的耦合性,提高系統的穩定性,降低並行開發引起的風險,提高程式碼的可讀性和可維護性。

依賴正置就是類間的依賴是實實在在的實現類間的依賴,也就是面向實現程式設計,這也是正常人的思維方式,我要開賓士車就依賴賓士車,我要使用膝上型電腦就直接依賴膝上型電腦,而編寫程式需要的是對現實世界的事物進行抽象,抽象的結構就是有了抽象類和介面,然後我們根據系統設計的需要產生了抽象間的依賴,代替了人們傳統思維中的事物間的依賴,“倒置”就是從這裡產生的。


5 .合成/聚合複用原則(Composite/Aggregate ReusePrinciple ,CARP):要儘量使用物件組合,而不是繼承關係達到軟體複用的目的

定義:經常又叫做合成複用原則(Composite ReusePrinciple或CRP),儘量使用物件組合,而不是繼承來達到複用的目的。

就是在一個新的物件裡面使用一些已有的物件,使之成為新物件的一部分;新物件通過向這些物件的委派達到複用已有功能的目的。簡而言之,要儘量使用合成/聚合,儘量不要使用繼承。

原則分析:

1)在面向物件設計中,可以通過兩種基本方法在不同的環境中複用已有的設計和實現,即通過 組合 / 聚合關係 或通過 繼承 繼承複用 :實現簡單,易於擴充套件。破壞系統的封裝性;從基類繼承而來的實現是靜態的,不可能在執行時發生改變,沒有足夠的靈活性;只能在有限的環境中使用。( “白箱”複用 組合/聚合複用 :耦合度相對較低,選擇性地呼叫成員物件的操作;可以在執行時動態進行。( “黑箱”複用 2) 組合 / 聚合可以 使系統更加靈活 ,類與類之間的 耦合度降低 ,一個類的變化對其他類造成的影響相對較少,因此一般 首選使用組合 / 聚合來實現複用 ;其次才考慮繼承,在使用繼承時,需要嚴格遵循里氏代換原則,有效使用繼承會有助於對問題的理解,降低複雜度,而濫用繼承反而會增加系統構建和維護的難度以及系統的複雜度,因此需要 慎重使用繼承複用 3)此原則和里氏代換原則氏相輔相成的,兩者都是具體實現"開-閉"原則的規範。違反這一原則,就無法實現"開-閉"原則,首先我們要明白合成和聚合的概念: 什麼是合成 ? 合成(組合):表示一個整體與部分的關係, 指一個依託整體而存在的關係( 整體與部分 不可以分開 ),例如:一個人對他的房子和傢俱,其中他的房子和傢俱是不能被共享的,因為那些東西都是他自己的。並且人沒了,這個也關係就沒了。這個例子就好像,烏雞百鳳丸這個產品,它是有烏雞和上等藥材合成而來的一樣。 也比如網路遊戲中的武器裝備合成一樣,多種東西合併為一種超強的東西一樣。 雖然組合表示的是一個整體與部分的關係,但是組合關係中部分和整體具有統一的生存期。一旦整體物件不存在,部分物件也將不存在,部分物件與整體物件之間具有同生共死的關係。 在組合關係中,成員類是整體類的一部分,而且整體類可以控制成員類的生命週期,即成員類的存在依賴於整體類。 在UML中,組合關係用帶實心菱形的直線表示。
原始碼:
public class Head{    private Mouth mouth;    public Head() {     mouth = new Mouth();    }}public class Mouth{}
  什麼是聚合 ? 聚合: 聚合是比合成關係的一種更強的依賴關係,也表示整體與部分的關係整體與部分可以分開,例如,一個賓士S360汽車,對賓士S360引擎,賓士S360輪胎的關係..這些關係就是帶有聚合性質的。因為賓士S360引擎和賓士S360輪胎他們只能被賓士S360汽車所用,離開了賓士S360汽車,它們就失去了存在的意義。在我們的設計中,這樣的關係不應該頻繁出現.這樣會增大設計的耦合度。 在面向物件中的聚合: 通常在定義一個整體類後,再去分析這個整體類的組成結構,從而找出一些成員類,該整體類和成員類之間就形成了聚合關係。 在聚合關係中, 成員類是整體類的一部分 ,即成員物件是整體物件的一部分,但是成員物件可以脫離整體物件獨立存在。 在UML中,聚合關係用帶空心菱形的直線表示。  比如汽車和汽車引擎:
public class Car{    private Engine engine;    public Car(Engine engine) {        this.engine = engine;    }    public void setEngine(Engine engine) {        this.engine = engine;    }}public class Engine{}
明白了合成和聚合關係,再來理解合成/聚合原則應該就清楚了。要避免在系統設計中出現,一個類的繼承層次超過3次。如果這樣的話,可以考慮重構你的程式碼,或者重新設計結構. 當然最好的辦法就是考慮使用合成/聚合原則。


6.迪米特法則(Law of Demeter,LoD系統中的類,儘量不要與其他類互相作用,減少類之間的耦合度

定義又叫最少知識原則(Least Knowledge Principle或簡寫為LKP)幾種形式定義:

(1) 不要和“陌生人”說話。英文定義為:Don't talk to strangers.

Ÿ(2) 只與你的直接朋友通訊。英文定義為:Talk only to your immediatefriends.

(3) 每一個軟體單位對其他的單位都只有最少的知識,而且侷限於那些與本單位密切相關的軟體單位

簡單地說,也就是,一個物件應當對其它物件有儘可能少的瞭解。一個類應該對自己需要耦合或呼叫的類知道得最少,你(被耦合或呼叫的類)的內部是如何複雜都和我沒關係,那是你的事情,我就知道你提供的public方法,我就呼叫這麼多,其他的一概不關心。

法則分析:

1)朋友類: 在迪米特法則中,對於一個物件,其朋友包括以下幾類: Ÿ (1) 當前物件本身 (this) Ÿ (2) 以引數形式傳入到當前物件方法中的物件; Ÿ (3) 當前物件的成員物件; Ÿ (4) 如果當前物件的成員物件是一個集合,那麼集合中的元素也都是朋友; Ÿ (5) 當前物件所建立的物件。 任何一個物件,如果滿足上面的條件之一,就是當前物件的“朋友”,否則就是“陌生人”。 2)狹義法則和廣義法則: 在狹義的迪米特法則中,如果兩個類之間不必彼此直接通訊 那麼這兩個類就不應當發生直接的相互作用 ,如果其中的一個類需要呼叫另一個類的某一個方法的話,可以通過 第三者轉發這個呼叫 。 
狹義的迪米特法則 :可以 降低類之間的耦合 ,但是會在系統中增加大量的小方法並散落在系統的各個角落,它可以使一個系統的區域性設計簡化,因為每一個區域性都不會和遠距離的物件有直接的關聯,但是也會 造成系統的不同模組之間的通訊效率降低 ,使得系統的不同模組之間不容易協調。 廣義的迪米特法則 指對物件之間的資訊流量、流向以及資訊的影響的控制 ,主要是 對資訊隱藏的控制 。資訊的隱藏可以使各個子系統之間脫耦,從而允許它們獨立地被開發、優化、使用和修改,同時可以促進軟體的複用,由於每一個模組都不依賴於其他模組而存在,因此每一個模組都可以獨立地在其他的地方使用。一個系統的規模越大,資訊的隱藏就越重要,而資訊隱藏的重要性也就越明顯。 3)迪米特法則的主要用途:在於控制資訊的過載。在類的劃分上,應當儘量 建立鬆耦合的類 ,類之間的耦合度越低,就越有利於複用,一個處在鬆耦合中的類一旦被修改,不會對關聯的類造成太大波及; 在類的結構設計上,每一個類都應當 儘量降低其成員變數和成員函式的訪問許可權 在類的設計上,只要有可能, 一個型別應當設計成不變類 在對其他類的引用上, 一個物件對其他物件的引用應當降到最低 例子: 外觀模式 前面提到:  設計模式(九)外觀模式Facade(結構型)

迪米特法則與設計模式Facade模式、Mediator模式使民無知

系統中的類,儘量不要與其他類互相作用,減少類之間的耦合度,因為在你的系統中,擴充套件的時候,你可能需要修改這些類,而類與類之間的關係,決定了修改的複雜度,相互作用越多,則修改難度就越大,反之,如果相互作用的越小,則修改起來的難度就越小..例如A類依賴B類,則B類依賴C類,當你在修改A類的時候,你要考慮B類是否會受到影響,而B類的影響是否又會影響到C類. 如果此時C類再依賴D類的話,呵呵,我想這樣的修改有的受了。


7.介面隔離法則(Interface Segregation Principle,ISL):客戶端不應該依賴那些它不需要的介面。(這個法則與迪米特法則是相通的

定義: 客戶端不應該依賴那些它不需要的介面 另一種定義方法:一旦一個介面太大,則需要將它分割成一些更細小的介面,使用該介面的客戶端僅需知道與之相關的方法即可。 注意 ,在該定義中的介面指的是所定義的方法。例如外面呼叫某個類的public方法。這個方法對外就是介面。 原則分析: 1) 介面隔離原則是指使 用多個專門的介面,而不使用單一的總介面 。每一個介面應該承擔一種相對獨立的角色,不多不少,不幹不該乾的事,該乾的事都要幹。       (1) 一個介面就 只代表一個角色 ,每個角色都有它特定的一個介面,此時這個原則可以叫做“角色隔離原則”。        (2) 介面 僅僅提供客戶端需要的行為 ,即所需的方法,客戶端不需要的行為則隱藏起來,應當為客戶端提供儘可能小的單獨的介面,而不要提供大的總介面。  2) 使用介面隔離原則拆分介面時,首先必須滿足 單一職責原則 ,將一組相關的操作定義在一個介面中,且在滿足高內聚的前提下,介面中的方法越少越好。 3) 可以在進行系統設計時採用 定製服務 的方式,即 為不同的客戶端提供寬窄不同的介面 ,只提供使用者需要的行為,而隱藏使用者不需要的行為。 例子: 下圖展示了一個擁有多個客戶類的系統,在系統中定義了一個巨大的介面(胖介面) AbstractService 來服務所有的客戶類。可以使用介面隔離原則對其進行重構。
重構後:
迪米特法則是目的,而介面隔離法則是對迪米特法則的規範. 為了做到儘可能小的耦合性,我們需要使用介面來規範類,用介面來約束類.要達到迪米特法則的要求,最好就是實現介面隔離法則,實現介面隔離法則,你也就滿足了迪米特法則。

原文地址:hguisu 面向物件設計模式原則詳解  http://blog.csdn.net/hguisu/article/details/7571617


           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述 你好! 這是你第一次使用 **Markdown編輯器** 所展示的歡迎頁。如果你想學習如何使用Markdown編輯器, 可以仔細閱讀這篇文章,瞭解一下Markdown的基本語法知識。

新的改變

我們對Markdown編輯器進行了一些功能拓展與語法支援,除了標準的Markdown編輯器功能,我們增加了如下幾點新功能,幫助你用它寫部落格:

  1. 全新的介面設計 ,將會帶來全新的寫作體驗;
  2. 在創作中心設定你喜愛的程式碼高亮樣式,Markdown 將程式碼片顯示選擇的高亮樣式 進行展示;
  3. 增加了 圖片拖拽 功能,你可以將本地的圖片直接拖拽到編輯區域直接展示;
  4. 全新的 KaTeX數學公式 語法;
  5. 增加了支援甘特圖的mermaid語法1 功能;
  6. 增加了 多螢幕編輯 Markdown文章功能;
  7. 增加了 焦點寫作模式、預覽模式、簡潔寫作模式、左右區域同步滾輪設定 等功能,功能按鈕位於編輯區域與預覽區域中間;
  8. 增加了 檢查列表 功能。

功能快捷鍵

撤銷:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜體:Ctrl/Command + I
標題:Ctrl/Command + Shift + H
無序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
檢查列表:Ctrl/Command + Shift + C
插入程式碼:Ctrl/Command + Shift + K
插入連結:Ctrl/Command + Shift + L
插入圖片:Ctrl/Command + Shift + G

合理的建立標題,有助於目錄的生成

直接輸入1次#,並按下space後,將生成1級標題。
輸入2次#,並按下space後,將生成2級標題。
以此類推,我們支援6級標題。有助於使用TOC語法後生成一個完美的目錄。

如何改變文字的樣式

強調文字 強調文字

加粗文字 加粗文字

標記文字

刪除文字

引用文字

H2O is是液體。

210 運算結果是 1024.

插入連結與圖片

連結: link.

圖片: Al   
 
 </div> 
 <div class=

相關推薦

設計模式原則

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

設計模式——單例模式

單例模式 你要做的只是複製程式碼去一步步驗證,至於原因程式碼中有;不懂可以聯絡我進行交流。 文中每一塊程式碼你可以直接複製貼上,不必要分開復制貼上單獨創捷類去執行。 /** * 單例模式總結: 單例模式優點 1、某些類建立比較頻繁,對於一些

設計模式——介面卡模式

介面卡模式 介面卡模式將某個類的介面轉換成客戶端期望的另一個介面表示,目的是消除由於介面不匹配所造成的類的相容性問題。主要分為三類:類的介面卡模式、物件的介面卡模式、介面的介面卡模式。 類的介面卡模式 當希望將一個類轉換成滿足另一個新介面的類時,可以使用類的介面

設計模式——裝飾模式

裝飾模式 就是給一個物件增加一些新的功能,而且是動態的,要求裝飾物件和被裝飾物件實現同一個介面,裝飾物件持有被裝飾物件的例項。 用處: 需要擴充套件一個類的功能。 動態的為一個物件增加功能,而且還能動態撤銷。(繼承不能做到這一點,繼承的功能是靜態的,不能

java設計模式例項

一、設計模式的分類總體來說設計模式分為三大類:建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。結構型模式,共七種:介面卡模式、裝飾器模式、代理模式、外觀模式、橋接模式、組

單例設計模式

靜態 對象 div oid 技術 bubuko 使用 方法 類型變量 單例設計模式 模式:模式就是解決一類問題的固定步驟 單例設計模式:保證一個類在內存中只有一個對象 舉例:多個瀏覽器向服務器發送請求,只創建一個servlet對象處理相應的請求,而不是每接收一個

設計模式的七大原則

## 1 認識設計模式 ### 1.1 什麼是設計模式 所謂設計模式,就是對經常出現的軟體設計問題的成熟解決方案。 很多人把設計模式想象成非常高深的概念,實際上設計模式僅僅是對特定問題的一種慣性思維。筆者見過一些學員喜歡抱著一本設計模式的書研究,以期成為一個“高手”,實際上設計模式的理解必須以足夠的程式碼積

設計模式六大原則

引言 對於設計模式,自己很早之前就看了好多本設計模式書籍,其中一些還看了好幾遍,也一直希望自己能在編碼的時候把這些設計模式用上去。可是,在日常的打碼中,用的做多的就是單例,其次是觀察者和建造者模式 ( builder ) 用得比較多,其他的基本很少用到。 用不到的原因是還是不能夠理解設計模式的思想,無法將這些

設計模式-單例模式(Singleton)

概述 定義 : 保證一個類僅有一個例項, 並提供一個全域性訪問點 又稱單件模式 型別 : 建立型 適用場景 想確保任何情況下都絕對只有一個例項 優點 在記憶體裡只有一個例項, 減少了記憶體開銷 可以避免對資源的多重

面向物件設計的七大設計原則

面向物件的七大設計原則 簡述 類的設計原則有七個,包括:開閉原則、里氏代換原則、迪米特原則(最少知道原則)、單一職責原則、介面分隔原則、依賴倒置原則、組合/聚合複用原則。 七大原則之間的關係 七大原則之間並不是相互孤立的,彼此間存在著一定關聯,一個可以是另

Java七大設計原則與運用

開心一笑 【婚禮上,氣氛正高著,主持人問新郎:”你會不會愛新娘一輩子?新郎興高采烈的喊:”會”。主持人:”你會不會在新娘容顏憔悴,疾病纏身的時候離開她? 猴急的新郎興高采烈的喊:”會”!】 課程介紹 Java七大設計原則在工作中是非常重要的

單一職責原則--七大面向物件設計原則(1)

單一職責原則來源:         定義:單一職責就是一個類負責一項職責.就一個類而言,應該只專注於做一件事和僅有一個引起它變化的原因。         所謂職責,我們可以理解為功能,就是設計的這個類功能應該只有一個,而不是兩個或更多。也可以理解為引用變化的原因,當你

設計模式 - 單例模式)看看和你理解的是否一樣?

一、概述 單例模式是設計模式中相對簡單且非常常見的一種設計模式,但是同時也是非常經典的高頻面試題,相信還是有很多人在面試時會掛在這裡。本篇文章主要針對單例模式做一個回顧,記錄單例模式的應用場景、常見寫法、針對執行緒安全進行除錯(看得見的執行緒)以及總結。相信大家看完這篇文章之後,對單例模式有一個非常深刻的認識

工匠家平臺系統開發類似滴滴打車模式app

機制 生活方式 醫院 系統 喜歡 個人 醫療 精彩 8.14 工匠家平臺系統開發(蘇銘.188.1414.7927)工匠家模式開發,工匠家平臺開發,工匠家公眾號平臺搭建,工匠家app開發,工匠家系統,做類似工匠家這樣的系統,做類似滴滴打車這樣的系統,開發工匠家這樣的平臺,開

萌店系統開發模式系統

app 上海 好的 供應鏈 實現 即時通訊 消費者 粉絲 統計數據 萌店系統開發(李想.185.6504.8478)O2O的優勢在於把網上和網下的優勢完美結合。通過網購導購機,把互聯網與地面店完美對接,實現互聯網落地。讓消費者在享受線上優惠價格的同時,又可享受線下貼身的服務

設計模式原則(3)--Dependency Inversion Principle(DIP)--依賴倒轉原則

以及 .get 依賴註入 不能 通過 而是 耦合度 面向實現 看書 1.定義:   高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。   抽象不應該依賴於細節,細節應當依賴於抽象。換言之,要針對接口編程,而不是針對實現編程。 2

支付寶小程序PHP全棧開發--前端樣式的設計.acss樣式

屏幕 類選擇器 兩種 項目結構 不包含 acs http 好的 undefined 關於.acss文件 在視頻中已經說過了,小程序的設計思想和原生app的設計思想頗為相似,基本的應用單元為頁面。當然對於一個頁面來說每一個元素的放置位置在哪兒以及顯示成什麽樣子這個是由樣式來決

Java單例模式深入

protected test 異常 except while 深入 bject his 不一致 Java單例模式深入詳解 一.問題引入   偶然想想到的如果把Java的構造方法弄成private,那裏面的成員屬性是不是只有通過static來訪問呢;如果構造方法是privat

C#中的IDisposable模式用法

數據庫 nor 是否 entry block 記錄日誌 自定義 技術分享 ssa 本文實例講述了C#中IDisposable模式的用法,針對垃圾資源的回收進行了較為詳細的講解。分享給大家供大家參考之用。具體方法如下: 首先,對於垃圾回收而言,在C#中,托管資源的垃圾回收是

西遊記之設計模式原則——單一職責原則

void 可能 equals main person 方法 隱患 客戶端代碼 p s 單一職責原則 ——專心致誌只做一件事 1 package danyizhize; 2 3 class SunWuKong { 4 public void XiangM