JAVA設(shè)計(jì)模式理解與總結(jié)(下)代理模式&適配器模式&觀察者模式

碼了好幾年代碼的打字機(jī)器我,對(duì)于設(shè)計(jì)模式這個(gè)詞,肯定是一點(diǎn)也不陌生,但是對(duì)于設(shè)計(jì)模式的理解,因?yàn)槿粘i_(kāi)發(fā)中,增刪改查較多,使用設(shè)計(jì)模式思想來(lái)優(yōu)化代碼的機(jī)會(huì)就很少。也不乏在翻閱源碼的時(shí)候,嘆服于別人優(yōu)秀高效的設(shè)計(jì)。所有今天抽出點(diǎn)時(shí)間,對(duì)設(shè)計(jì)模式做個(gè)歸納、記錄,以便日后讀到優(yōu)秀的源碼,可以自信的說(shuō),這**不就是那啥嗎,我也會(huì)寫(xiě)~~~

設(shè)計(jì)模式

設(shè)計(jì)模式(Design Pattern)是前輩們對(duì)代碼開(kāi)發(fā)經(jīng)驗(yàn)的總結(jié),是解決特定問(wèn)題的一系列套路。它不是語(yǔ)法規(guī)定,而是一套用來(lái)提高代碼可復(fù)用性、可維護(hù)性、可讀性、穩(wěn)健性以及安全性的解決方案

代理模式

一個(gè)類(lèi)代表另一個(gè)類(lèi)的功能,在代理模式中,我們創(chuàng)建具有現(xiàn)有對(duì)象的對(duì)象,以便向外界提供功能接口。

代理模式在我們的生活中也很常見(jiàn),例如程序員的女友想買(mǎi)一個(gè)法國(guó)產(chǎn)的某包包,她不需要親自去法國(guó)某個(gè)賣(mài)驢的專(zhuān)賣(mài)店去買(mǎi),而是可以在代購(gòu)手中購(gòu)買(mǎi),并獲得一些小禮物,折扣優(yōu)惠等等。

靜態(tài)代理

在代碼中,代理就是在使用者和服務(wù)提供者中間的服務(wù),提供一些在提供的服務(wù)前后處理一些事物的功能。

賣(mài)東西人的認(rèn)證(共同實(shí)現(xiàn)的接口)

public interface Seller {
    void sell();
}

法國(guó)某經(jīng)銷(xiāo)商:

public class LvFactory implements Seller{
    @Override
    public void sell() {
        System.out.println("LV廠家賣(mài)包包");
    }
}

你女朋友朋友圈某個(gè)不知名好友:

class Purchase implements Seller{
    private Seller seller;

    public Purchase(Seller factory) {
        this.seller = factory;
    }

    @Override
    public void sell() {
        System.out.println("坐飛機(jī)去法國(guó)");
        seller.sell();
        System.out.println("坐飛機(jī)回國(guó)");
    }
}

你女朋友:

public static void main(String[] args) {
    Seller lv = new LvFactory();
    new Purchase(lv).sell();
}

你:

信用卡 boom~~~~~~~~~~~~~~~~~

坐飛機(jī)去法國(guó)

LV廠家賣(mài)包包

坐飛機(jī)回國(guó)

動(dòng)態(tài)代理

動(dòng)態(tài)代理有別于靜態(tài)代理,是根據(jù)代理的對(duì)象,動(dòng)態(tài)創(chuàng)建代理類(lèi)。這樣,就可以避免靜態(tài)代理中代理類(lèi)接口過(guò)多的問(wèn)題。動(dòng)態(tài)代理是實(shí)現(xiàn)方式,是通過(guò)反射來(lái)實(shí)現(xiàn)的,借助Java自帶的java.lang.reflect.Proxy,通過(guò)固定的規(guī)則生成。

舉個(gè)??,女朋友朋友圈這個(gè)代購(gòu),代購(gòu)包,也代購(gòu)手表,那我找他一起買(mǎi)一塊手表呢?

手表接口和天梭類(lèi):

public interface Watch {
    void sellWatch();
}
public class TissotWatch implements Watch {
    @Override
    public void sellWatch() {
        System.out.println("賣(mài)天梭手表");
    }
}

使用 InvocationHandler 定義代理類(lèi):

public class PurchaseProxy implements InvocationHandler {
    private Object object;
    public PurchaseProxy(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("坐飛機(jī)出國(guó)");
        Object result = method.invoke(object, args);
        System.out.println("坐飛機(jī)回國(guó)");
        return result;
    }
}

在朋友圈買(mǎi)包買(mǎi)表:

public static void main(String[] args) {
    //賣(mài)包
    Seller lvseller = new LvFactory();
    PurchaseProxy lvproxy = new PurchaseProxy(lvseller);
    ((Seller) Proxy.newProxyInstance(lvseller.getClass().getClassLoader(), new Class[] { Seller.class }, lvproxy)).sell();
    //賣(mài)表
    Watch tissot = new TissotWatch();
    PurchaseProxy tissotproxy = new PurchaseProxy(tissot);
    ((Watch) Proxy.newProxyInstance(tissot.getClass().getClassLoader(), new Class[] { Watch.class }, tissotproxy)).sellWatch();
}

坐飛機(jī)出國(guó)

LV廠家賣(mài)包包

坐飛機(jī)回國(guó)

坐飛機(jī)出國(guó)

賣(mài)天梭手表

坐飛機(jī)回國(guó)

動(dòng)態(tài)代理詳解

InvocationHandler

InvocationHandler 是一個(gè)接口,當(dāng)代理方法被調(diào)用時(shí),會(huì)調(diào)用起相對(duì)應(yīng)的實(shí)現(xiàn)類(lèi)的 invoke 方法。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    return null;
}

三個(gè)參數(shù):

  • proxy 代理對(duì)象
  • method 代理對(duì)象調(diào)用的方法
  • args 調(diào)用的方法中的參數(shù)
Proxy

Java自帶的java.lang.reflect.Proxy

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
  • loader 類(lèi)加載器
  • interfaces 代碼要用來(lái)代理的接口
  • h 一個(gè) InvocationHandler 對(duì)象

適配器模式

我們?nèi)粘J褂玫倪m配器是一個(gè)接口轉(zhuǎn)換器,它可以是一個(gè)獨(dú)立的硬件接口設(shè)備,允許硬件或電子接口與其它硬件或電子接口相連,也可以是信息接口

在代碼中,我想實(shí)現(xiàn)一個(gè)接口中的部分功能,或者想用一個(gè)類(lèi)來(lái)冒充另一個(gè)類(lèi)來(lái)實(shí)現(xiàn)它的功能,就需要適配器模式了。

適配器模式使接口不兼容的那些類(lèi)可以一起工作,其別名為包裝器

類(lèi)適配器模式

在類(lèi)適配器模式中,適配器與適配者之間是繼承,適配著實(shí)現(xiàn)通用接口

舉個(gè)??,我國(guó)標(biāo)準(zhǔn)電壓是220v,手機(jī)充電器也是220v,日本標(biāo)準(zhǔn)電壓是110v,女朋友去日本玩,想給220v的手機(jī)用110v電壓充電,就需要一個(gè)適配器了。

日本插座:

public class JapanAC {
    private final static int v = 110;
    public void jcharge() {
        System.out.printf("使用%dv電壓充電\n", v);
    }
}

充電通用接口:

public interface Charger {
    void charge();
}

買(mǎi)一個(gè) 110v升220變壓器:

public class Adaptee extends JapanAC implements Charger {
    @Override
    public void charge() {
        System.out.println("使用適配器110v轉(zhuǎn)220v");
        super.jcharge();
        System.out.println("充電完成");
    }
}

女朋友使用適配器充電:

public static void main(String[] args) {
    Charger charger = new Adaptee();
    charger.charge();
}

使用適配器110v轉(zhuǎn)220v

使用110v電壓充電

充電完成

對(duì)象適配器模式

把一只猴子偽裝成人:

有那么一種猴子:

public interface Monkey {
    //吃香蕉
    void eatBanana();
    //騎獨(dú)輪車(chē)
    void rideABike();
}
public class Shuang implements Monkey {
    @Override
    public void eatBanana() {
        System.out.println("猴子吃香蕉");
    }
    @Override
    public void rideABike() {
        System.out.println("猴子獨(dú)輪車(chē)"); //猴子不懂人性,只會(huì)騎獨(dú)輪車(chē)
    }
}

有那么個(gè)人:

public interface Human {
    //吃香蕉
    void eatBanana();
    //開(kāi)車(chē)
    void drive();
}
public class Da implements Human{
    @Override
    public void eatBanana() {
        System.out.println("人吃香蕉");
    }
    @Override
    public void drive() {
        System.out.println("人開(kāi)車(chē)");
    }
}

猴子偽裝成人的大型真猴修表演:

public class MonkeyMan implements Human{
    private Monkey monkey;
    public MonkeyMan(Monkey monkey) {
        this.monkey = monkey;
    }
    @Override
    public void eatBanana() {
        monkey.eatBanana();
    }
    @Override
    public void drive() {
        monkey.rideABike();
    }
}

猴子偽裝成人:

public static void main(String[] args) {
    Monkey shuang = new Shuang();
    Human human = new MonkeyMan(shuang); //猴子成人
    human.drive();
}

猴子獨(dú)輪車(chē)

觀察者模式

當(dāng)對(duì)象間存在一對(duì)多關(guān)系時(shí),則使用觀察者模式(Observer Pattern)。比如,當(dāng)一個(gè)對(duì)象被修改時(shí),則會(huì)自動(dòng)通知依賴(lài)它的對(duì)象。觀察者模式屬于行為型模式。

又被稱(chēng)為發(fā)布-訂閱(Publish/Subscribe)模式

例如微博關(guān)注,多個(gè)用戶(hù)關(guān)注同一博主,博主更新,會(huì)通知到所有用戶(hù)。

羅老師微博:

public interface Bloger {
    void add(Fan fan);
    void del(Fan fan);
    void notifySms(String sms);
}
public class Luo implements Bloger {
    private List<Fan> fans;
    {
        fans = new ArrayList<>();
    }
    @Override
    public void add(Fan fan) {
        fans.add(fan);
    }
    @Override
    public void del(Fan fan) {
        fans.remove(fan);
    }
    @Override
    public void notifySms(String sms) {
        fans.forEach(fan -> fan.notifySms(sms));
    }
}

粉絲:

public interface Fan {
    void notifySms(String sms);
}
public class Xigua implements Fan {
    private String name;
    public Xigua(String name) {
        this.name = name;
    }
    @Override
    public void notifySms(String sms) {
        System.out.println(name + " | " + sms);
    }
}

羅老師直播買(mǎi)手機(jī) :

public static void main(String[] args) {
    Fan leijun = new Xigua("雷軍");
    Fan dongmingzhu = new Xigua("董明珠");
    Fan renzhengfei = new Xigua("任正非");

    Bloger luo = new Luo();
    luo.add(leijun);
    luo.add(dongmingzhu);
    luo.add(renzhengfei);

    luo.notifySms("買(mǎi)錘子,送錘子啦?。?!");
}

雷軍 | 買(mǎi)錘子,送錘子啦!??!

董明珠 | 買(mǎi)錘子,送錘子啦?。?!

任正非 | 買(mǎi)錘子,送錘子啦?。?!

實(shí)際生產(chǎn)過(guò)程中,觀察者模式往往用消息中間件來(lái)實(shí)現(xiàn)

收工





更多好玩好看的內(nèi)容,歡迎到我的博客交流,共同進(jìn)步????????WaterMin


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容