DAY00

設計模式

什麼是設計模式?

他是一套提高代碼複用性,健壯性,可讀性,安全性的方案

設計模式的分類

  • 按目的
  • 按作用範圍

23中設計模式簡介

  1. Singleton-單例模式:某個類只能生成一個對象。

  2. Prototype-原型模式:把某個對象作爲原型,對其進行復制從而創建出多個與該原型類似新新對象

  3. Factory Method-工廠方法模式:定義一個創建對象的接口,具體生成什麼對象,由子類來實現

  4. Abstract Factory-抽象工廠模式:提供一個創建對象族的接口,每個子類可以生成一系列的對象

  5. Builder-建造者模式:將一個複雜的對象分解成多個相對簡單的部分,根據不同的需求去創建他們,最後構成該複雜對象

  6. Proxy-代理模式:爲對象提供一個種代理來控制對該對象的訪問

  7. Bridge-橋接模式:將抽象與實現分離,使他們可以單獨變化,降低抽象與實現的耦合度

  8. Adapter-適配器模式:創建一個新類(即適配器類)使得原來接口不兼容不能一起工作的類能一起工作

  9. Dectorator-裝飾器模式:動態的爲對象添加額外的功能

  10. Factor-外觀模式:爲多個複雜的子系統提供一個一致的接口,使得這些子系統更加容易被訪問

  11. FlyWeight-享元模式:通過共享技術有效的支持大量細粒度對象的複用

  12. Composite-組合模式:將對象組合成樹狀層次結構,使得單個對象和組合對象的訪問具有一致性

  13. TemplateMethod-模板方法模式:定義一個算法框架,將算法的一些步驟延遲到子類,子類可以在不改變該算法結構的前提下,重寫算法的一些步驟

  14. Strage-策略模式:定義一組算法,並將每個算法封裝,使得他們可以自由切換。

  15. Command-命令模式:將請求封裝成一個對象,使得發出請求的責任與執行請求的責任分隔開。

  16. Chain-of-Reposibility-責任鏈模式:將請求從一個對象傳遞到另一個對象,知道請求被響應,以此來降低對象間的耦合度。

  17. State-狀態模式:一個對象在內部狀態改變時改變能夠其行爲。

  18. Observer-觀察者模式:多個對象間存在一對多的關係,當其中一種對象發生改變時,能夠將改變通知給其他對象,從而影響其他對象的行爲。

  19. Mediator-中介者模式:通過定義一箇中介對象來簡化原有對象之間的交互關係,降低對象間的耦合度。

  20. Iterator-迭代器模式:提供了一種方法來訪問聚合對象中的一系列數據,而不暴露元素的內部表示

  21. Visitor-訪問者模式:在不訪問集合元素的前提下,爲元素提供多種訪問方式,即每個元素有多個訪問者對象訪問。

  22. Memento-備忘錄模式:在不破壞對象封裝性的前提下,訪問並保存對象的內部狀態,在需要的時候恢復對象。

  23. Interpreter-解釋器模式:提供瞭如何定義語言的方法,以及如何解釋語言子句的方法。

範圍\目的 創建型模式 結構型模式 行爲型模式
類模式 工廠方法 (類)適配器 模板方法
解釋器
對象模式 單例
原型
抽象工廠
建造者
代理
(對象)適配器
橋接
裝飾
外觀
享元
組合
策略
命令
職責鏈
狀態
觀察者
中介者
迭代器
訪問者
備忘錄

類之間的關係

依賴關係

是一種使用關係,是臨時性的關聯,耦合度最低的一種關係

表現形式

  • 局部變量
  • 方法參數
  • 靜態方法調用

表示方法:帶箭頭的虛線

關聯關係

用來表示對象之間的聯繫,如丈夫-妻子,老師-學生,可以是單向也可以是雙向的

表現形式:一個類的對象作爲另一個類的成員變量,即成員對象的形式

  • 一般關聯關係
    • 表示對象間的聯繫
    • 表示方法:帶箭頭的實線
  • 聚合關係
    • 表示對象間是部分與整體的關係,是has-a關係,但是成員對象可以脫離整體對象而獨立存在,如學校與老師的關係,學校停辦了,老師依舊存在
    • 表示方法:帶空心菱形的實線
  • 組合關係
    • 也是表示對象間是部分與整體的關係,是cxmtains-a的關係,整體對象可以控制成員對象的生命週期,但是成員對象不可以脫離整體對象而獨立存在,如頭和嘴的關係,沒有了頭,嘴就不存在了
    • 表示方法:帶實心菱形的實線

泛化關係

類與類之間耦合度最高一種關係,表示一般與特殊的關係

  • 表現形式:java的繼承

  • 表示方法:帶空心三角的實線

實現關係

即接口與實現類之間的關係

  • 表示方法:帶空心三角的虛線

總結:沒有帶實心三角的,哈哈

7條常見的原則

口訣:開理依,單結(結)合體(迪)

開閉原則(Open Closed Principle,OCP)

定義:當應用需求發生改變時,在不修改源代碼或二進制代碼的前提下,擴展模塊功能

核心內容:軟件實體應該對擴展開放,對修改封閉

軟件實體分爲三部分

  • 模塊
  • 類與接口
  • 方法

實現方式:可以通過“抽象約束,封裝變化”的方式來實現開閉原則,通過接口或抽象類爲接口定義一個相對穩定的抽象層,而可變因素則是封裝在具體的實現類中

作用:

  • 對軟件測試的影響:只需要測試拓展的代碼即可
  • 提高代碼的可複用性:粒度越小,可複用性越大
  • 提高軟件的可維護性和穩定性

里氏替換原則(Liskov Substitution Principle,LSP,Liskov:里斯科夫)

定義:繼承必須保證基類擁有的特性在派生類仍然成立(像不敢改革的領導)

核心內容:指明瞭什麼時候應該使用繼承,什麼時候不該使用繼承,子類可以擴展父類的功能,但是不能修改父類的功能,如企鵝,鴕鳥從生物學上講他們都是鳥類,但是他們不能繼承鳥類會“飛”的功能。

實現方式:

  • 子類可以擴展父類的功能,但不能修改父類的功能

作用:

  • 里氏替換是實現開閉原則的重要方式之一
  • 克服了繼承中重寫父類造成可複用性變差的缺點
  • 類的擴展不會給現有系統引入新的錯誤,即降低代碼出錯的可能性

依賴倒置原則(Dependence Inversion Principle,DIP)

定義:高層模塊不應該依賴於底層模塊,兩者都應該依賴於其抽象,因爲抽象不依賴於其細節,而細節卻依賴於抽象。

核心內容:要面向接口編程,不應該面向實現編程,他是開閉原則的重要實現之一,降低了客戶和實現模塊之間的耦合度

實現方式:

  • 每個類儘量提供接口或抽象類,或者兩者都具備。
  • 變量的聲明類型儘量是接口或者是抽象類。
  • 任何類都不應該從具體類派生。
  • 使用繼承時儘量遵循里氏替換原則。

作用:

  • 降低類之間的耦合度
  • 提高代碼的可讀性和可維護性
  • 提高系統的穩定性
  • 減少並行開發引起的風險(因爲接口和抽象類寫好了契約)

例子:

interface Shop {
    void selling();
}

class BeiJingShop implements Shop{
    @Override
    public void selling() {
        System.out.println("北京特產:北京烤鴨,北京酥糖");
    }
}

class ShangHaiShop implements Shop {

    @Override
    public void selling() {
        System.out.println("上海特產:上海水蜜桃,上海浦東雞");
    }
}

class Cumtomer {
    public void shopping(Shop shop) {
        shop.selling();
    }
}

public class DIP {
    public static void main(String[] args) {
        BeiJingShop beiJingShop = new BeiJingShop();
        ShangHaiShop shangHaiShop = new ShangHaiShop();
        Cumtomer cumtomer = new Cumtomer();
        System.out.println("顧客購買以下商品");
        cumtomer.shopping(beiJingShop);
        cumtomer.shopping(shangHaiShop);
    }
}
//output
顧客購買以下商品
北京特產:北京烤鴨,北京酥糖
上海特產:上海水蜜桃,上海浦東雞

單一職責原則(Single Responsibility Principle,SRP,又稱單一功能原則)

定義:一個類應該有且只有一個引起他變化的原因,否則這個類應該被拆分(即拆分類)

如果一個類承擔了太多職責的缺點:

  • 某個職責的變化可能會抑制這個類實現其他職責的能力
  • 客戶端只需要某個職責時,不得不將其他職責包含進來,造成冗餘代碼

實現方式:

  • 根據職責拆分類

作用:

  • 降低代碼的複雜度,一個類只負責一個職責
  • 提高提高代碼的可讀性和可維護性:可讀性提高了,可維護性也提高了
  • 變更引起的風險降低,變更是必然的,當修改一個功能時,可以顯著的降低對其他功能的影響

例子:學生工作中:生活由輔導員管理,而學業由指導老師管,而不是都丟給其中一個老師

接口隔離原則(Interface Segregation Principle,ISP)

定義:一個類對另一個類的依賴應該建立在最小的接口上(即儘量拆分接口)

實現方式:

  • 接口儘量小,但要有限度,一個接口只服務於一個子模塊
  • 瞭解環境,拒絕盲從,環境不同,接口拆分的原則不同,需要深入瞭解業務邏輯
  • 爲依賴接口的類定製方法,只提供調用者需要的方法

作用:

  • 將臃腫的接口拆分成粒度小的接口,提高系統的靈活性
  • 降低代碼的冗餘度
  • 提高系統的可讀性和可維護性

例子:學生成績管理程序,分三個接口:錄入模塊,計算模塊,打印模塊

合成複用原則(Composite Reuse Principle,CRP)

合成複用又稱組合/聚合複用

通常類的複用分:繼承複用與組合/聚合複用

繼承複用的缺點:

  • 父類子類耦合度高,限制了類的擴展性,父類的任何修改都會導致子類發生發生變化
  • 降低了靈活度,父類繼承來的實現都是編譯時已確定
  • 破壞了類的封裝性,繼承會把父類的實現細節暴露給子類

合成複用的優點:

  • 維護了封裝性,成員對象的內部細節是不可見的
  • 耦合度降低,整體對象調用成員對象的唯一方法是通過成員對象提供的接口
  • 提高了靈活度,動態的指定成員對象

例子:汽車分類管理程序

迪米特法則(Law of Demeter,LoD)

又名:最少知識原則

定義:如果兩個軟件實體不發生直接通信,則不應該產生直接相互調用,而應該通過第三方轉發調用

作用:

  • 降低耦合度(變成“一般關聯”關係,而不是“泛化”關係),提高模塊的獨立性
  • 提高了獨立性意味着可複用性提高

強調的點:

  • 從依賴者的角度,只依賴該依賴的對象
  • 從被依賴者的角度,只暴露該暴露的方法

運用法則的注意事項:

  • 應當創建弱耦合的類
  • 降低成員變量的訪問權限
  • 需私有成員的提供訪問方法
  • 慎重使用序列化

例子:助理,明星,粉絲,影視公司

class Star {
    private String name;
    public Star(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Fan {
    private String name;

    public Fan(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Company {
    private String name;
    public Company(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}
class Agent {
    private Star star;
    private Company company;
    private Fan fan;

    public void setStar(Star star) {
        this.star = star;
    }

    public void setCompany(Company company) {
        this.company = company;
    }

    public void setFan(Fan fan) {
        this.fan = fan;
    }

    public void meeting() {
        System.out.println(star.getName()+" 與 "+fan.getName()+" 見面");
    }

    public void business() {
        System.out.println(star.getName()+" 與 "+company.getName()+" 合作");
    }
}
public class LOD {
    public static void main(String[] args) {
        Agent agent = new Agent();
        agent.setCompany(new Company("唐人影視有限公司"));
        agent.setFan(new Fan("曾小哥"));
        agent.setStar(new Star("唐仁"));
        agent.business();
        agent.meeting();
    }
}
//output
唐仁 與 唐人影視有限公司 合作
唐仁 與 曾小哥 見面
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章