23種設計模式實例詳解(一)

一、簡介

   軟件設計模式(Design pattern),又稱設計模式,是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性、程序的重用性。

二、六大原則

1、開閉原則

   開閉原則(Open Close Principle)的意思是:對擴展開放,對修改關閉。在程序需要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。簡言之,是爲了使程序的擴展性好,易於維護和升級。想要達到這樣的效果,我們需要使用接口和抽象類,後面的具體設計中我們會提到這點。

2、里氏代換原則

   里氏代換原則(Liskov Substitution Principle)是面向對象設計的基本原則之一。 里氏代換原則中說,任何基類可以出現的地方,子類一定可以出現。LSP 是繼承複用的基石,只有當派生類可以替換掉基類,且軟件單位的功能不受到影響時,基類才能真正被複用,而派生類也能夠在基類的基礎上增加新的行爲。里氏代換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,所以里氏代換原則是對實現抽象化的具體步驟的規範。

3、依賴倒轉原則

   依賴倒轉原則(Dependence Inversion Principle)是開閉原則的基礎,具體內容:針對接口編程,依賴於抽象而不依賴於具體。

4、接口隔離原則

   接口隔離原則(Interface Segregation Principle)的意思是:使用多個隔離的接口,比使用單個接口要好。它還有另外一個意思是:降低類之間的耦合度。由此可見,其實設計模式就是從大型軟件架構出發、便於升級和維護的軟件設計思想,它強調降低依賴,降低耦合。

5、最少知道原則

   迪米特法則,又稱最少知道原則(Demeter Principle)是指:一個實體應當儘量少地與其他實體之間發生相互作用,使得系統功能模塊相對獨立。

6、合成複用原則

  合成複用原則(Composite Reuse Principle)是指:儘量使用合成/聚合的方式,而不是使用繼承。

三、實例詳解

總體來說設計模式分爲三大類:

  • 創建型模式(5種):工廠模式、抽象工廠模式、單例模式、構建者模式、原型模式。
  • 結構型模式(7種):適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
  • 行爲型模式(11種):策略模式、模板模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

根據分類,我畫了一份腦圖,如下圖:
在這裏插入圖片描述

1、工廠模式

  定義一個用於創建產品的接口,由子類決定生產什麼產品。典型的案例:JDBC連接數據庫,通過加載不同的數據庫驅動,得到不同的數據庫連接。

Phone類:手機標準規範類

public interface Phone {
    void make();
}

HuaWeiPhone類:製造華爲手機

public class HuaWeiPhone implements Phone{
    @Override
    public void make() {
        System.out.println("make huawei phone");
    }
}

XiaoMiPhone類:製造小米手機

public class XiaoMiPhone implements Phone{
    @Override
    public void make() {
        System.out.println("make xiaomi phone");
    }
}

PhoneFactory類:手機代工廠(Factory)

public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        if(phoneType.equalsIgnoreCase("xiaomi")){
            return new XiaoMiPhone();
        }
        else if(phoneType.equalsIgnoreCase("huawei")) {
            return new HuaWeiPhone();
        }
        return null;
    }
}

演示:

public class Demo {
    public static void main(String[] args) {
        PhoneFactory phoneFactory = new PhoneFactory();
        Phone huawei = phoneFactory.makePhone("huawei");
        huawei.make();
        Phone xiaomi = phoneFactory.makePhone("xiaomi");
        xiaomi.make();
    }
}

控制檯輸出:

make huawei phone
make xiaomi phone

2、抽象工廠模式

  提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。例如,創建小米工廠和華爲工廠,生產多個產品(手機、電腦、電視…)。

Phone類:手機標準規範類

public interface Phone {
    void make();
}

HuaWeiPhone類:製造華爲手機

public class HuaWeiPhone implements Phone{
    @Override
    public void make() {
        System.out.println("make huawei phone");
    }
}

XiaoMiPhone類:製造小米手機

public class XiaoMiPhone implements Phone{
    @Override
    public void make() {
        System.out.println("make xiaomi phone");
    }
}

AbstractFactory類:抽象工廠類

public interface AbstractFactory {
    Phone makePhone();
}

XiaoMiFactory類:製造小米產品的工廠

public class XiaoMiFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {
        return new XiaoMiPhone();
    }
}

HuaWeiFactory類:製造華爲產品的工廠

public class HuaWeiFactory implements AbstractFactory{
    @Override
    public Phone makePhone() {
        return new HuaWeiPhone();
    }
}

演示:

public class Demo {
    public static void main(String[] args) {
        HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
        Phone huawei = huaWeiFactory.makePhone();
        huawei.make();
        XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();
        Phone xiaomi = xiaoMiFactory.makePhone();
        xiaomi.make();
    }
}

控制檯輸出:

make huawei phone
make xiaomi phone

3、單例模式

  某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。例如,一些設備管理器常常設計爲單例模式,比如一個電腦有兩臺打印機,在輸出的時候就要處理不能兩臺打印機打印同一個文件。

Singleton類:懶漢式,線程安全。

  • 優點:第一次調用才初始化,避免內存浪費。
  • 缺點:必須加鎖 synchronized 才能保證單例,但加鎖會影響效率。
public class Singleton {
    private static Singleton instance;
    private Singleton (){}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Singleton類:餓漢式,線程安全

  • 優點:沒有加鎖,執行效率會提高。
  • 缺點:類加載時就初始化,浪費內存。
public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}

4、構建者模式

  將一個複雜對象分解成多個相對簡單的部分,然後根據不同需要分別創建它們,最後構建成該複雜對象。例如:電腦是顯示器、鍵盤、鼠標等等組成使用的,但客戶只需購買就可以了,無需關注產品內部組成的細節。

  • Product:最終要生成的對象,例如 Computer實例。
  • Builder:構建者的抽象基類(有時會使用接口代替)。其定義了構建Product的抽象步驟,其實體類需要實現這些步驟。其會包含一個用來返回最終產品的方法Product getProduct()。
  • ConcreteBuilder:Builder的實現類。
  • Director:決定如何構建最終產品的算法. 其會包含一個負責組裝的方法void Construct(Builder builder), 在這個方法中通過調用builder的方法,就可以設置builder,等設置完成後,就可以通過builder的 getProduct() 方法獲得最終的產品。

PC類:電腦標準規範類

public class PC {
    private String keyboard;//鍵盤
    private String mouse;//鼠標
    private String monitor;//顯示器
    private String master;//主機

    public PC(String keyboard, String mouse) {
        this.keyboard = mouse;
        this.mouse = mouse;
    }

    public void setMonitor(String monitor) {
        this.monitor = monitor;
    }

    public void setMaster(String master) {
        this.master = master;
    }

    @Override
    public String toString() {
        return "PC{" +
                "keyboard='" + keyboard + '\'' +
                ", mouse='" + mouse + '\'' +
                ", monitor='" + monitor + '\'' +
                ", master='" + master + '\'' +
                '}';
    }
}

PCBuilder類:抽象構建者類

public abstract class PCBuilder {
    public abstract void setMonitor();
    public abstract void setMaster();

    public abstract PC getPC();
}

MacPCBuilder類:蘋果電腦構建者類

public class MacPCBuilder extends PCBuilder {
    private PC pc;

    public MacPCBuilder(String keyboard, String mouse) {
        pc = new PC(keyboard, mouse);
    }

    @Override
    public void setMonitor() {
        pc.setMonitor("蘋果顯示器");
    }

    @Override
    public void setMaster() {
        pc.setMaster("蘋果主機");
    }

    @Override
    public PC getPC() {
        return pc;
    }
}

MiPCBuilder類:小米電腦構建者類

public class MiPCBuilder extends PCBuilder {
    private PC pc;

    public MiPCBuilder(String keyboard, String mouse) {
        pc = new PC(keyboard, mouse);
    }

    @Override
    public void setMonitor() {
        pc.setMonitor("小米顯示器");
    }

    @Override
    public void setMaster() {
        pc.setMaster("小米主機");
    }

    @Override
    public PC getPC() {
        return pc;
    }
}

PCDirector類:指導者類

public class PCDirector {
    public void makePC(PCBuilder builder){
        builder.setMonitor();
        builder.setMaster();
    }
}

演示:

public class Demo {
    public static void main(String[] args) {
        PCDirector director=new PCDirector();
        PCBuilder builder=new MacPCBuilder("德國櫻桃鍵盤","羅技鼠標");
        director.makePC(builder);
        PC macPC=builder.getPC();
        System.out.println("mac pc:"+macPC.toString());

        PCBuilder miPCBuilder=new MiPCBuilder("ikbc鍵盤","雷柏鼠標");
        director.makePC(miPCBuilder);
        PC miPC=miPCBuilder.getPC();
        System.out.println("mi pc:"+miPC.toString());
    }
}

控制檯輸出:

mac pc:PC{keyboard='羅技鼠標', mouse='羅技鼠標', monitor='蘋果顯示器', master='蘋果主機'}
mi pc:PC{keyboard='雷柏鼠標', mouse='雷柏鼠標', monitor='小米顯示器', master='小米主機'}

5、原型模式

  將一個對象作爲原型,通過對其進行復制而克隆出多個和原型類似的新實例。
  這種模式是實現了一個原型接口,該接口用於創建當前對象的克隆。當直接創建對象的代價比較大時,則採用這種模式。例如,一個對象需要在一個高代價的數據庫操作之後被創建。我們可以緩存該對象,在下一個請求時返回它的克隆,在需要的時候更新數據庫,以此來減少數據庫調用。

Shape類:實現了Cloneable接口的抽象類

public abstract class Shape implements Cloneable {

    private String id;
    protected String type;

    abstract void buy();

    public String getType(){
        return type;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Object clone() {
        Object clone = null;
        try {
            clone = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

Apple類:蘋果類

public class Apple extends Shape {

    public Apple(){
        type = "Apple";
    }

    @Override
    public void buy() {
        System.out.println("buy() method: Apple");
    }
}

Banana類:香蕉類

public class Banana extends Shape {

    public Banana(){
        type = "Banana";
    }

    @Override
    public void buy() {
        System.out.println("buy() method: Banana");
    }
}

Orange類:橙子類

public class Orange extends Shape {

    public Orange(){
        type = "Orange";
    }

    @Override
    public void buy() {
        System.out.println("buy() method: Orange");
    }
}

ShapeCache類:

public class ShapeCache {

    private static HashMap<String, Shape> shapeMap = new HashMap<String, Shape>();

    public static Shape getShape(String shapeId) {
        Shape cachedShape = shapeMap.get(shapeId);
        return (Shape) cachedShape.clone();
    }

    // 對每種水果都運行數據庫查詢,並創建該水果。shapeMap.put(shapeKey, shape);
    public static void loadCache() {
        Apple apple = new Apple();
        apple.setId("1");
        shapeMap.put(apple.getId(),apple);

        Banana banana = new Banana();
        banana.setId("2");
        shapeMap.put(banana.getId(),banana);

        Orange orange = new Orange();
        orange.setId("3");
        shapeMap.put(orange.getId(),orange);
    }
}

演示:

public class Demo {
    public static void main(String[] args) {
        ShapeCache.loadCache();

        Shape clonedShape = (Shape) ShapeCache.getShape("1");
        System.out.println("Shape : " + clonedShape.getType());

        Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
        System.out.println("Shape : " + clonedShape2.getType());

        Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
        System.out.println("Shape : " + clonedShape3.getType());
    }
}

控制檯輸出:

Shape : Apple
Shape : Banana
Shape : Orange
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章