聊一聊設計模式(三)-- 結構型設計模式

ClericYi發表於2020-02-21

聊一聊設計模式(三)-- 結構型設計模式

前言

憋在家裡的第8天,今天開始進入結構型設計模式。

思維導圖

聊一聊設計模式(三)-- 結構型設計模式

結構型設計模式是從程式的結構上解決模組之間的耦合問題。

代理模式

定義:為其他物件提供一種代理以控制對這個物件的訪問。

聊一聊設計模式(三)-- 結構型設計模式

這個模式的幾個角色分為以下:

  1. Subject:抽象主題類。
  2. RealSubject:真實主題類,客戶端由Proxy來間接呼叫。
  3. Proxy:代理類

這個模式就像你和代購的存在一樣,你提出需求,由代購來幫你購買。這個句子裡基本上就概括了整個代理模式的全貌。客戶端就是我們需求者,而真實主題就是你要找的代購幫你買,最後一個代理,找誰買。 以下用程式碼表示靜態代理。

/**
 * 抽象主題類
 * 中心主題,買東西。
 */
public interface Shop {
    void buy();
}

/**
 * 真實主題類
 * 有這麼一個人,可以幹這件事,他就是代理
 */
public class Person implements Shop {
    @Override
    public void buy() {
        System.out.println("購買");
    }
}

/**
 * 代理類
 * 你要告訴自己找那個代購買
 */
public class WhoBuy implements Shop {
    private Shop shop;

    WhoBuy(Shop shop){
        this.shop = shop;
    }
    @Override
    public void buy() {
        shop.buy();
    }
}

/**
 * 客戶端類
 * 就是這個想買東西的人了
 */
public class User {
    public static void main(String[] args) {
        Shop person = new Person();
        Shop purchase = new WhoBuy(person);
        purchase.buy();
    }
}
複製程式碼

靜態代理,主要是為了讓人更好的理解代理模式。在開發中主要還是使用反射機制來完成的,也就是動態代理模式。

/**
 * 動態代理類
 */
public class DynamicPurchase implements InvocationHandler {
    private Object object;
    DynamicPurchase(Object object){
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        if(method.getName().equals("buy")){
            System.out.println("買上");
        }
        return result;
    }
}

/**
 * 客戶端類
 */
public class User {
    public static void main(String[] args) {
        Shop person = new Person();
        DynamicPurchase dynamicPurchase = new DynamicPurchase(person);
        ClassLoader loader = person.getClass().getClassLoader();
        Shop purchase = (Shop) Proxy.newProxyInstance(loader, new Class[]{Shop.class}, dynamicPurchase);
        purchase.buy();
    }
}
複製程式碼

和靜態代理的不同就在於代理類,使用反射機制。 這種代理模式的優點:

  1. 真實主題類只關注本身的業務邏輯。
  2. 真實主題類和代理類實現了公共介面,不必擔心主題類的修改影響代理類。

裝飾模式

動態地給一個物件新增一些額外的職責。

聊一聊設計模式(三)-- 結構型設計模式

這個模式的角色有:

  1. Component:抽象元件。
  2. ConcreteComponent:元件具體實現類。
  3. Decorator:抽象裝飾者,用於增加Component類的功能。
  4. ConcreteDecorator:裝飾者的具體實現

人是一個慢慢學習的生物,從一開始只會咿咿呀呀,經過學習,學會了數學,英語。這個時候數學、英語,兩個科目就是一種裝飾了。

/**
 * 抽象元件
* 作為一個人,必然會有學習的能力。
 */
public abstract class Person {
    public abstract void learn();
}

/**
 * 元件具體實現類
 * 人一開始只會咿咿呀呀
 */
public class Me extends Person {
    @Override
    public void learn() {
        System.out.println("咿咿呀呀");
    }
}

/**
 * 抽象裝飾類
 * 有一個老師教書育人
 */
public abstract class Teacher extends Person {
    
    private Person person;
    
    Teacher(Person person){
        this.person = person;
    }    
    @Override
    public void learn() {
        person.learn();
    }
}

/**
 * 裝飾具體類
 * 這個老師教數學,也就教會了孩子
 */
public class MathTeacher extends Teacher {
    MathTeacher(Person person) {
        super(person);
    }

    public void teach(){
        System.out.println("學會了數學");
    }

    @Override
    public void learn() {
        super.learn();
        teach();
    }
}

// 具體使用
public class Main {
    public static void main(String[] args) {
        Person person = new Me();
        MathTeacher mathTeacher = new MathTeacher(person);
        mathTeacher.learn();
    }
}
複製程式碼

優點:

  1. 能夠動態的為物件增加功能。
  2. 裝飾類和元件類互不干擾。 缺點:
  3. 不論是裝飾類,還是元件類都繼承自Component,如果Component發生了改變,子類必然收到巨大的衝擊。
  4. 裝飾層數不宜過多,不僅影響效率,排查也比較苦難。

外觀模式

要求一個子系統 的外部與內部的通訊必須通過一個統一的物件進行。

聊一聊設計模式(三)-- 結構型設計模式

這個模式的角色有:

  1. Facade:外觀類
  2. Subsystem:子系統類

這裡覺得之前看到的武俠的例子非常好。 一個武俠本身分為招式、內功、經脈三個系統,每次放招都是根據三個子系統的合理使用來釋放。

/**
 * 三大子系統
 */
public class 經脈 {
    public void jingmai(){
        System.out.println("開啟經脈");
    }
}

public class 內功 {
    public void JiuYang(){
        System.out.println("使用九陽神功");
    }

    public void QianKun(){
        System.out.println("使用乾坤大挪移");
    }
}

public class 招式 {
    public void QiShangQuan(){
        System.out.println("使用七傷拳");
    }

    public void ShengHuoLing(){
        System.out.println("使用聖火令");
    }
}

/**
 * 外觀類
 * 也就是張無忌
 */
public class 張無忌 {
    private JingMai jingMai;
    private NeiGong neiGong;
    private ZhaoShi zhaoShi;
    
    張無忌(){
        jingMai = new JingMai();
        neiGong = new NeiGong();
        zhaoShi = new ZhaoShi();
    }
    
    public void QianKun(){
        jingMai.jingmai();
        neiGong.QianKun();
    }
    
    public void QiShang(){
        jingMai.jingmai();
        neiGong.JiuYang();
        zhaoShi.QiShangQuan();
    }
}
複製程式碼

給外人看到的只有張無忌的出招是七傷拳,但是不知道內部的具體操作,這也就是外觀類的整體展現方式了。 優點:

  1. 所有的依賴都是出現在外觀類的,子系統間互不干擾。
  2. 具體實現對使用者隱藏,也就是使用者和子系統處於鬆耦合狀態,同時保障了子系統的安全性。 缺點:業務一旦出現變更,就需要直接修改外觀類。

享元模式

使用共享物件有效地支援大量細粒度的物件。

聊一聊設計模式(三)-- 結構型設計模式

該模式下的物件有

  1. Flyweight:抽象享元角色。
  2. ConcreteFlyweight:具體享元角色
  3. FlyweightFactory:享元工廠,負責物件建立和管理。

其實往簡單了說就是一種緩衝池的技術。

/**
 * 享元工廠
 */
public class VipFactory {
    private static Map<String, Vip> cache = new HashMap<>(); 
    public static Vip getVip(String number){
        if(cache.containsKey(number)){
            return cache.get(number);
        }else{
            Vip vip = new Vip(number);
            cache.put(number, vip);
            return vip;
        }
    }
}

/**
 * 享元角色
 */
public class Vip implements IVip {
    private String name;
    private String number;

    Vip(String number){
        this.number = number;
    }

    @Override
    public void showVip(String number) {
        if (number.equals(number)) {
            System.out.println(name == null? "空": name);
        }
    }
}

/**
 * 享元抽象角色
 */
public interface IVip {
    void showVip(String number);
}
複製程式碼

在享元工廠中我們顯而易見的看到了由static修飾的cache變數,這就是一個緩衝,如果緩衝中存在,就從緩衝中取,不存在則建立。

以上就是我的學習成果,如果有什麼我沒有思考到的地方或是文章記憶體在錯誤,歡迎與我分享。


相關文章推薦:

聊一聊設計模式(一)-- 六大原則

聊一聊設計模式(二)-- 建立型設計模式

聊一聊設計模式(四)-- 行為型設計模式

相關文章