JAVA設(shè)計(jì)模式相關(guān)

轉(zhuǎn)自JsonChao的GitHub
https://github.com/JsonChao/Awesome-Android-Notebook/edit/master/notes/Android%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%85%E9%A1%BB%E6%8E%8C%E6%8F%A1%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md

一、設(shè)計(jì)模式六大原則

設(shè)計(jì)模式有六大原則,如下所示:

  • 單一職責(zé)原則
  • 開(kāi)放封閉原則
  • 里氏替換原則
  • 依賴倒置
  • 迪米特原則
  • 接口隔離原則

單一職責(zé)原則

一個(gè)類應(yīng)該僅有一個(gè)引起它變化的原因惕它,即不要讓一個(gè)類承擔(dān)過(guò)多的職責(zé),以此降低耦合性因块。

開(kāi)放封閉原則

類、函數(shù)籍铁、模塊應(yīng)該是可以擴(kuò)展的涡上,但是不可以修改,即對(duì)擴(kuò)展開(kāi)放寨辩,修改封閉吓懈。

里氏替換原則

所有引用基類的地方都能透明地替換為子類對(duì)象,即可以在定義時(shí)盡量使用基類對(duì)象靡狞,等到運(yùn)行時(shí)再確定其子類類型耻警,用子類對(duì)象來(lái)替換父類對(duì)象。

依賴倒置原則

高層甸怕、底層模塊甘穿、模塊間和細(xì)節(jié)都應(yīng)該依賴于抽象,即通過(guò)接口或抽象類產(chǎn)生依賴關(guān)系梢杭。

迪米特原則

一個(gè)軟件實(shí)體應(yīng)該盡可能少地與其它實(shí)體發(fā)生相互作用温兼,即最少知識(shí)原則。

如果一個(gè)對(duì)象需要調(diào)用其它對(duì)象的某個(gè)方法武契,可以通過(guò)第三者來(lái)調(diào)用募判,這個(gè)第三者的作用就如Android中的事件總線EventBus一樣荡含。

接口隔離原則

一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上。

二届垫、設(shè)計(jì)模式分類

GoF提出的設(shè)計(jì)模式有23種释液,按照目的準(zhǔn)則分類,有三大類:

  • 創(chuàng)建性設(shè)計(jì)模式5種:?jiǎn)卫按Α⒐S方法误债、抽象工廠、建造者妄迁、原型寝蹈。
  • 結(jié)構(gòu)型設(shè)計(jì)模式7種:適配器、裝飾登淘、代理箫老、外觀、橋接黔州、組合槽惫、享元。
  • 行為型設(shè)計(jì)模式11種:策略辩撑、模板方法、觀察者仿耽、迭代器合冀、責(zé)任鏈、命令项贺、備忘錄君躺、狀態(tài)、訪問(wèn)者开缎、中介者棕叫、解釋器。

三奕删、Android開(kāi)發(fā)常用設(shè)計(jì)模式

1俺泣、創(chuàng)建型設(shè)計(jì)模式

單例模式

保證一個(gè)類僅有一個(gè)實(shí)例,提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)完残。

單例模式共有5種寫法:

1伏钠、餓漢模式
public class Singleton {
    private static Singleton instance = new Singleton;
    private Singleton () {
        
    }
    public static Singleton getInstance() {
        return instance;
    }
}
  • 在類加載的時(shí)候就完成實(shí)例化,如果從始至終未使用這個(gè)實(shí)例谨设,則會(huì)造成內(nèi)存的浪費(fèi)熟掂。
2、懶漢模式(線程安全)
public class Singletion {
    private static Singleton instance;
    private Singleton () {
    }
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 為了處理并發(fā)扎拣,每次調(diào)用getInstance方法時(shí)都需要進(jìn)行同步赴肚,會(huì)有不必要的同步開(kāi)銷素跺。
3、雙重檢查模式(DCL)
public class Singleton {
    private static volatile Singleton instance;
    private Singleton {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 第一次判空誉券,省去了不必要的同步指厌。第二次是在Singleton等于空時(shí)才創(chuàng)建實(shí)例。
  • 使用volatile保證了實(shí)例的可見(jiàn)性横朋。
  • DCL在一定程度上解決了資源的消耗和多余的同步仑乌、線程安全等問(wèn)題,但是在某些情況下會(huì)失效琴锭。

假設(shè)線程A執(zhí)行到instance = new Singleton()語(yǔ)句晰甚,看起來(lái)只有一行代碼,但實(shí)際上它并不是原子操作决帖,這句代碼最終會(huì)被編譯成多條匯編指令厕九,它大致做了3件事:

1)給instance的實(shí)例分配內(nèi)存。

2)調(diào)用Singleton()構(gòu)造函數(shù)地回,初始化成員字段扁远。

3)將instance對(duì)象指向分配的內(nèi)存空間(此時(shí)instance就不是null了)。

但是刻像,由于Java編譯器允許處理器亂序執(zhí)行畅买,以及JDK1.5之前JMM中的Cache、寄存器到主內(nèi)存回寫順序的規(guī)定细睡,上面的2和3的順序是無(wú)法保證的谷羞,也就是說(shuō),執(zhí)行順序可能是1-2-3也可能是1-3-2溜徙。如果是后者湃缎,并且在3執(zhí)行完畢、2未執(zhí)行之前蠢壹,被切換到線程B上嗓违,這時(shí)候instance因?yàn)橐呀?jīng)在線程A內(nèi)執(zhí)行過(guò)了3,instance已經(jīng)是非空了图贸,所以蹂季,線程B直接取走instance,再使用時(shí)就會(huì)出錯(cuò)求妹,這就是DCL失效問(wèn)題乏盐,而且這種難以跟蹤難以重現(xiàn)的錯(cuò)誤可能會(huì)隱藏很久。

在JDK1.5之后制恍,SUN官方已經(jīng)注意到這種問(wèn)題父能,調(diào)整了JVM,具體化了volatile關(guān)鍵字净神,因此何吝,如果JDK1.5或之后的版本溉委,只需要將instance的定義改成private volatile static Singleton instance = null就可以保證instance對(duì)象每次都是從主內(nèi)存中讀取,就可以使用DCL的寫法來(lái)完成單例模式爱榕。當(dāng)然瓣喊,volatile或多或少也會(huì)影響到性能,但考慮到程序的正確性黔酥,這點(diǎn)犧牲也是值得的藻三。

DCL優(yōu)點(diǎn):資源利用率高,第一次執(zhí)行g(shù)etInstance時(shí)單例對(duì)象才會(huì)被實(shí)例化跪者,效率高棵帽。

缺點(diǎn):第一次加載稍慢,也由于JMM的原因?qū)е屡紶枙?huì)失敗渣玲。在高并發(fā)環(huán)境下也有一定的缺陷逗概,雖然發(fā)生概率很小。DCL模式是使用最多的單例實(shí)現(xiàn)方式忘衍,它能夠在需要時(shí)才實(shí)例化對(duì)象逾苫,并且能在絕大多數(shù)場(chǎng)景下保證對(duì)象的唯一性,除非你的代碼在并發(fā)場(chǎng)景比較復(fù)雜或低于JDK1.6版本下使用枚钓,否則铅搓,這種方式一般能夠滿足要求。

4搀捷、靜態(tài)內(nèi)部類單例模式
public class Singleton() {
    private Singleton() {
    }
    public static Singleton getInstance() {
        return SingletonHolder.sInstance;
    }
    private static class SingletonHolder {
        private static final Singleton sInstance = new Singleton();
    }
}
  • 第一次調(diào)用getInstance方法時(shí)虛擬機(jī)才加載SingletonHolder并初始化sInstance狸吞,這樣保證了線程安全和實(shí)例的唯一性。
5指煎、枚舉單例
public enum Singleton {
    INSTANCE;
    public void doSomeThing() {
    }
}
  • 默認(rèn)枚舉實(shí)例的創(chuàng)建是線程安全的,并且在任何情況下都是單例便斥。
  • 簡(jiǎn)單至壤、可讀性不高。

注意:上面的幾種單例模式創(chuàng)建的單例對(duì)象被反序列化時(shí)會(huì)重新創(chuàng)建實(shí)例枢纠,可以重寫readReslove方法返回當(dāng)前的單例對(duì)象像街。

簡(jiǎn)單工廠模式(補(bǔ)充)

也稱為靜態(tài)工廠方法模式,由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例晋渺。

簡(jiǎn)單工廠模式中有如下角色:

  • 工廠類:核心镰绎,負(fù)責(zé)創(chuàng)建所有實(shí)例的內(nèi)部邏輯,由外界直接調(diào)用木西。
  • 抽象產(chǎn)品類:要?jiǎng)?chuàng)建所有對(duì)象的抽象父類畴栖,負(fù)責(zé)描述所有實(shí)例所共有的公共接口。
  • 具體產(chǎn)品類:要?jiǎng)?chuàng)建的產(chǎn)品八千。
簡(jiǎn)單示例

1吗讶、抽象產(chǎn)品類

public abstract class Computer {
    public abstarct void start();
}

2燎猛、具體產(chǎn)品類

public class LenovaComputer extends Computer {
    @Override
    public void start() {
        ...
    }
}

public class HpComputer extends Computer {
    @Override
    public void start() {
        ...
    }
}

public class AsusComputer extends Computer {
    @Override
    public void start() {
        ...
    }
}

3、工廠類

public class ComputerFactory {
    public static Computer createComputer(String type) {
        Computer mComputer = null;
        switch (type) {
            case "lenovo":
                mComputer = new LenovoComputer();
                break;
            case "hp":
                mComputer = new HpComputer();
                break;
            case "asus":
                mComputer = new AsusComputer();
                break;
        }
        return mComputer;
    }
}
  • 它需要知道所有工廠類型照皆,因此只適合工廠類負(fù)責(zé)創(chuàng)建的對(duì)象比較少的情況重绷。
  • 避免直接實(shí)例化類,降低耦合性膜毁。
  • 增加新產(chǎn)品需要修改工廠昭卓,違背開(kāi)放封閉原則。

工廠方法模式

定義一個(gè)用于創(chuàng)建對(duì)象的接口瘟滨,使類的實(shí)例化延遲到子類候醒。

工廠方法有以下角色:

  • 抽象產(chǎn)品類。
  • 具體產(chǎn)品類室奏。
  • 抽象工廠類:返回一個(gè)泛型的產(chǎn)品對(duì)象火焰。
  • 具體工廠類:返回具體的產(chǎn)品對(duì)象。
簡(jiǎn)單示例

抽象產(chǎn)品類和具體產(chǎn)品類同簡(jiǎn)單工廠一樣胧沫。

3昌简、抽象工廠類

public abstract class ComputerFactory {
    public abstract <T extends Computer> T createComputer(Class<T> clz);
}

4、具體工廠類

public class GDComputerFactory extends ComputerFactory {
    @Override
    public <T extends Computer> T createComputer(Class<T> clz) {
        Computer computer = null;
        String classname = clz.getName();
        try {
            computer = (Computer) Class.forName(classname).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) computer;
    }
}
  • 相比簡(jiǎn)單工廠绒怨,如果我們需要新增產(chǎn)品類纯赎,無(wú)需修改工廠類,直接創(chuàng)建產(chǎn)品即可南蹂。

建造者模式

將一個(gè)復(fù)雜對(duì)象的構(gòu)建和它的表示分離犬金,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。

建造者有以下角色:

  • 導(dǎo)演類:負(fù)責(zé)安排已有模塊的安裝順序六剥,最后通知建造者開(kāi)始建造晚顷。
  • 建造者:抽象Builder類,用于規(guī)范產(chǎn)品的組建疗疟。
  • 具體建造者:實(shí)現(xiàn)抽象Builder類的所有方法该默,并返回建造好的對(duì)象。
  • 產(chǎn)品類策彤。
簡(jiǎn)單示例

1栓袖、產(chǎn)品類

public class Computer {
    private String mCpu;
    private Stiring mMainboard;
    private String mRam;
    public void setmCpu(String mCpu) {
        this.mCpu = mCpu;
    }
    public void setmMainboard(String mMainboard) {
        this.mMainboard = mMainboard;
    }
    public void setmRam(String mRam) {
        this.mRam = mRam;
    }
}

2、抽象建造者

public abstract class Builder {
    public abstract void buildCpu(String cpu);
    public abstract void buildMainboard(String mainboard);
    public abstract void buildRam(String ram);
    public abstract Computer create();
}

3店诗、具體建造者

public class MoonComputerBuilder extends Builder {
    private Computer mComputer = new Computer();
    
    @Override
    public void buildCpu(String cpu) {
        mComputer.setmCpu(cpu);
    }
    
    @Override
    public void buildMainboard(String mainboard) {
        mComputer.setmMainboard(mainboard);
    }
    
    @Override
    public void buildRam(String ram) {
        mComputer.setmRam(ram);
    }
    
    @Override
    public Computer create() {
        return mComputer;
    }
}

4裹刮、導(dǎo)演類

public class Director {
    Builder mBuilder = null;
    public Director (Builder builder) {
        this.mBuilder = builder;
    }
    
    public Computer createComputer(String cpu, String mainboard, String ram) {
        this.mBuilder.buildCpu(cpu);
        this.mBuilder.buildMainboard(mainboard);
        this.mBuilder.buildRam(ram);
        return mBuilder.create();
    }
}
  • 屏蔽產(chǎn)品內(nèi)部組成細(xì)節(jié)。
  • 具體建造者類之間相互獨(dú)立庞瘸,容易擴(kuò)展捧弃。
  • 會(huì)產(chǎn)生多余的建造者對(duì)象和導(dǎo)演類。

2擦囊、結(jié)構(gòu)型設(shè)計(jì)模式

1塔橡、代理模式

為其它對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪問(wèn)梅割。

代理模式中有以下角色:

  • 抽象主題類:聲明真實(shí)主題和代理的共同接口方法。
  • 真實(shí)主題類葛家。
  • 代理類:持有對(duì)真實(shí)主題類的引用户辞。
  • 客戶端類。
靜態(tài)代理示例代碼

1癞谒、抽象主題類

public interface IShop {
    void buy();
}

2底燎、真實(shí)主題類

public class JsonChao implements IShop {
    @Override 
    public void buy() {
        ...
    }
}

3、代理類

public class Purchasing implements IShop {
    private IShop mShop;
    public Purchasing(IShop shop) {
        this.mShop = shop;
    }
    
    @Override 
    public void buy() {
        mShop.buy();
    }
}

4弹砚、客戶端類

public class Clent {
    
    public static void main(String[] args) {
        IShop jsonChao = new JsonChao();
        IShop purchasing = new Purchasing(jsonChao);
        purchasing.buy();
    }
}
動(dòng)態(tài)代理

在代碼運(yùn)行時(shí)通過(guò)反射來(lái)動(dòng)態(tài)地生成代理類的對(duì)象双仍,并確定到底來(lái)代理誰(shuí)。

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

改寫靜態(tài)代理的代理類和客戶端類桌吃,如下所示:

1朱沃、動(dòng)態(tài)代理類

public class DynamicPurchasing implements InvocationHandler {
    private Object obj;
    public DynamicPurchasing(Object obj) {
        this.obj = obj;
    }
    
    @Overrdie
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(obj, args);
    }
}

2、客戶端類

public class Clent {
    
    public static void main(String[] args) {
        IShop jsonChao = new JsonChao();
        DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(jsonChao);
        ClassLoader cl = jsonChao.getClass.getClassLoader();
        IShop purchasing = Proxy.newProxyInstance(cl, new Class[]{IShop.class}, mDynamicPurchasing);
        purchasing.buy();
    }
}
  • 真實(shí)主題類發(fā)生變化時(shí)茅诱,由于它實(shí)現(xiàn)了公用的接口逗物,因此代理類不需要修改。

裝飾模式

動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)瑟俭。

裝飾模式有以下角色:

  • 抽象組件:接口/抽象類翎卓,被裝飾的最原始的對(duì)象。
  • 具體組件:被裝飾的具體對(duì)象摆寄。
  • 抽象裝飾者:擴(kuò)展抽象組件的功能失暴。
  • 具體裝飾者:裝飾者具體實(shí)現(xiàn)類。
示例代碼

1微饥、抽象組件

public abstract class Swordsman {
    public abstract void attackMagic();
}

2逗扒、具體組件

public class YangGuo extends Swordsman {
    @Override
    public void attackMagic() {
        ...
    }
}

3、抽象裝飾者

抽象裝飾者必須持有抽象組件的引用欠橘,以便擴(kuò)展功能缴阎。

public abstract class Master extends Swordsman {
    private Swordsman swordsman;
    public Master(Swordsman swordsman) {
        this.swordman = swordman;
    }
    
    @Override
    public void attackMagic() {
        swordsman.attackMagic();
    }
}

4、具體裝飾者

public class HongQiGong extends Master {
    public HongQiGong(Swordsman swordsman) {
        this.swordsman = swordsman;
    }
    
    public void teachAttackMagic() {
        ...
    }
    
    @Override
    public void attackMagic() {
        super.attackMagic();
        teackAttackMagic();
    }
}

5简软、使用

YangGuo mYangGuo = new YangGuo();
HongQiGong mHongQiGong = new HongQiGong(mYangGuo);
mHongQiGong.attackMagic(); 
  • 使用組合,動(dòng)態(tài)地?cái)U(kuò)展對(duì)象的功能述暂,在運(yùn)行時(shí)能夠使用不同的裝飾器實(shí)現(xiàn)不同的行為痹升。
  • 比繼承更易出錯(cuò),旨在必要時(shí)使用畦韭。

外觀模式(門面模式)

一個(gè)子系統(tǒng)的內(nèi)部和外部通信必須通過(guò)一個(gè)統(tǒng)一的對(duì)象進(jìn)行疼蛾。即提供一個(gè)高層的接口,方便子系統(tǒng)更易于使用艺配。

外觀模式有以下角色:

  • 外觀類:將客戶端的請(qǐng)求代理給適當(dāng)?shù)淖酉到y(tǒng)對(duì)象察郁。
  • 子系統(tǒng)類:可以有一個(gè)或多個(gè)子系統(tǒng)衍慎,用于處理外觀類指派的任務(wù)。注意子系統(tǒng)不含外觀類的引用皮钠。
簡(jiǎn)單示例

1稳捆、子系統(tǒng)類(這個(gè)有三個(gè)子系統(tǒng))

public class ZhaoShi {
    public void TaiJiQuan() {
        ...
    }
    
    public void QiShanQuan() {
        ...
    }
    
    public void ShengHuo() {
        ...
    }
}

public class NeiGong {
    public void JiuYang() {
        ...
    }
    
    public void QianKun() {
        ...
    }
}

public class JingMai {
    public void JingMai() {
        ...
    }
}

2、外觀類

public class ZhangWuJi {
    private ZhaoShi zhaoShi;
    private JingMai jingMai;
    pirvate Neigong neiGong;
    
    public ZhangWuJi() {
        zhaoShi = new ZhaoShi();
        jingMai = new JingMai();
        neiGong = new NeiGong();
    }
    
    public void qianKun() {
        jingMai.JingMai();
        neiGong.QianKun();
    }
    
    public void qiShang() {
        jingMai.JingMai();
        neiGong.JiuYang();
        zhaoShi.QiShangQuan();
    }
}

3麦轰、使用

ZhangWuJi zhangWuJi = new ZhangWuJi();
zhangWuJi.QianKun();
zhangWuJi.QiShang();
  • 將對(duì)子系統(tǒng)的依賴轉(zhuǎn)換為對(duì)外觀類的依賴乔夯。
  • 對(duì)外部隱藏子系統(tǒng)的具體實(shí)現(xiàn)。
  • 這種外觀特性增強(qiáng)了安全性款侵。

享元模式

使用共享對(duì)象有效支持大量細(xì)粒度(性質(zhì)相似)的對(duì)象末荐。

額外的兩個(gè)概念:

  • 1、內(nèi)部狀態(tài):共享信息新锈,不可改變甲脏。
  • 2、外部狀態(tài):依賴標(biāo)記妹笆,可以改變块请。

享元模式有以下角色:

  • 抽象享元角色:定義對(duì)象內(nèi)部和外部狀態(tài)的接口。
  • 具體享元角色:實(shí)現(xiàn)抽象享元角色的任務(wù)晾浴。
  • 享元工廠:管理對(duì)象池及創(chuàng)建享元對(duì)象负乡。
簡(jiǎn)單示例

1、抽象享元角色

public interface IGoods {
    public void showGoodsPrice(String name);
}

2脊凰、具體享元角色

public class Goods implements IGoods {
    private String name;
    private String price;
    
    Goods (String name) {
        this.name = name;
    }
    
    @Override
    public void showGoodsPrice(String name) {
        ...
    }
}

3抖棘、享元工廠

public class GoodsFactory {
    private static Map<String, Goods> pool = new HashMap<String, Goods>();
    public static Goods getGoods(String name) {
        if (pool.containsKey(name)) {
            return pool.get(name);
        } else {
            Goods goods = new Goods(name);
            pool.put(name, goods);
            return goods;
        }
    }
}

4、使用

Goods goods1 = GoodsFactory.getGoods("Android進(jìn)階之光");
goods1.showGoodsPrice("普通版");
Goods goods2 = GoodsFactory.getGoods("Android進(jìn)階之光");
goods1.showGoodsPrice("普通版");
Goods goods3 = GoodsFactory.getGoods("Android進(jìn)階之光");
goods1.showGoodsPrice("簽名版");

goods1為新創(chuàng)建的對(duì)象狸涌,后面的都是從對(duì)象池中取出的緩存對(duì)象切省。

適配器模式

將一個(gè)接口轉(zhuǎn)換為另一個(gè)需要的接口。

適配器有以下角色:

  • 要轉(zhuǎn)換的接口帕胆。
  • 要轉(zhuǎn)換的接口的實(shí)現(xiàn)類朝捆。
  • 轉(zhuǎn)換后的接口。
  • 轉(zhuǎn)換后的接口的實(shí)現(xiàn)類懒豹。
  • 適配器類芙盘。
簡(jiǎn)單示例

1、要轉(zhuǎn)換的接口(火雞)

public interface Turkey {
    public void gobble();
    public void fly();
}

2脸秽、要轉(zhuǎn)換的接口的實(shí)現(xiàn)類

public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
        ...
    }
    
    @Override
    public void fly() {
        ...
    }
}

3儒老、轉(zhuǎn)換后的接口(鴨子)

public interface Duck {
    public void quack();
    public void fly();
}

4、轉(zhuǎn)換后的接口的實(shí)現(xiàn)類记餐。

public class MallardDuck implements Duck {
    @Override
    public void quack() {
        ...
    }
    
    @Overrdie
    public void fly() {
        ...
    }
}

5驮樊、適配器類

public class TurkeyAdapter implements Duck {
    Turkey turkey;
    
    public TurkeyAdapter(Turkey turkey) {
        this.turkey = turkey;
    }
    
    @Override
    public void quack() {
        turkey.gobble();
    }
    
    @Override
    public void fly() {
        // 火雞沒(méi)有鴨子飛的遠(yuǎn),因此多飛幾次,達(dá)到適配鴨子fly的作用
        for(int i;i < 5;i++) {
            turkey.fly();
        }
    }
}

6囚衔、使用

WildTurkey wildTurkey = new WildTurkey();
TurkeyAdapter turkeyAdapter = new TurkeyAdapter(wildTurkey);
turkeyAdapter.quack();
turkeyAdapter.fly();
  • 注重適度使用即可挖腰。

3、行為型設(shè)計(jì)模式

1练湿、策略模式

定義一系列的算法猴仑,將每一個(gè)算法都封裝起來(lái),并且可相互替換鞠鲜。這使得算法可以獨(dú)立于調(diào)用者而單獨(dú)變化宁脊。

策略模式有以下角色:

  • 上下文角色:用來(lái)操作策略使用的上下文環(huán)境。屏蔽了高層模塊對(duì)策略和算法的直接訪問(wèn)贤姆。
  • 抽象策略角色榆苞。
  • 具體策略角色。
簡(jiǎn)單示例

1霞捡、抽象策略角色

public interface FightingStrategy {
    public void fighting();
}

2坐漏、具體策略角色

public class WeakRivalStrategy implements FightingStrategy {
    
    @Override
    public void fighting() {
        ...
    }
}

public class CommonRivalStrategy implements FightingStrategy {
    
    @Override
    public void fighting() {
        ...
    }
}

public class StrongRivalStrategy implements FightingStrategy {
    
    @Override
    public void fighting() {
        ...
    }
}

3、上下文角色

public class Context {
    private FightingStrategy mFightingStrategy;
    
    public void Context(FightingStrategy fightingStrategy) {
        this.mFightingStrategy = fightingStrategy;
    }
    
    public void fighting() {
        mFightingStrategy.fighting();
    }
}

4碧信、使用

Context context;
context = new Context(new WeakRivalStrategy());
context.fighting();
context = new Context(new CommonRivalStategy());
context.fighting();
context = new Context(new StrongRivalStategy());
context.fighting();
  • 隱藏具體策略中算法的實(shí)現(xiàn)細(xì)節(jié)赊琳。
  • 避免使用多重條件語(yǔ)句。
  • 易于擴(kuò)展
  • 每一個(gè)策略都是一個(gè)類砰碴,復(fù)用性小躏筏。
  • 上層模塊必須知道有哪些策略類,與迪米特原則相違背呈枉。

2趁尼、模板方法模式

定義了一套算法框架,將某些步驟交給子類去實(shí)現(xiàn)猖辫。使得子類不需改變框架結(jié)構(gòu)即可重寫算法中的某些步驟酥泞。

模板方法模式有以下角色:

  • 抽象類:定義了一套算法框架。
  • 具體實(shí)現(xiàn)類啃憎。
簡(jiǎn)單示例

1芝囤、抽象類

public abstract class AbstractSwordsman {

    public final void fighting() {
        neigong();
        
        // 這個(gè)是具體方法
        jingmai();
        
        if (hasWeapons()) {
            weapons();
        }
        
        moves();
        
        hook();
    }
    
    protected void hook() { };
    protected void abstract neigong();
    protected void abstract weapons();
    protected void abstract moves();
    public void jingmai() {
        ...
    }
    
    protected boolean hasWeapons() {
        return ture;
    }
}

2、具體實(shí)現(xiàn)類

public class ZhangWuJi extends AbstractSwordsman {
    
    @Override
    public void neigong() {
        ...
    }
    
    @Override 
    public void weapons() {
        // 沒(méi)有武器辛萍,不做處理
    }
    
    @Override 
    public void moves() {
        ...
    }
    
    @Override
    public boolean hasWeapons() {
        return false;
    }
}

punlc class ZhangSanFeng extends AbstractSwordsman {
    
    @Override
    public void neigong() {
        ...
    }
    
    @Override 
    public void weapons() {
        ...
    }
    
    @Override 
    public void moves() {
        ...
    }
    
    @Override
    public void hook() {
        // 額外處理
        ...
    }
}

3悯姊、使用

ZhangWuJi zhangWuJi = new ZhangWuJi();
zhangWuJi.fighting();
ZhangSanFeng zhangSanFeng = new ZhangSanFeng();
zhangSanFeng.fighting();
  • 可以使用hook方法實(shí)現(xiàn)子類對(duì)父類的反向控制。
  • 可以把核心或固定的邏輯搬移到基類贩毕,其它細(xì)節(jié)交給子類實(shí)現(xiàn)悯许。
  • 每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類,復(fù)用性小耳幢。

3、觀察者模式(發(fā)布 - 訂閱模式)

定義對(duì)象間的一種1對(duì)多的依賴關(guān)系,每當(dāng)這個(gè)對(duì)象的狀態(tài)改變時(shí)睛藻,其它的對(duì)象都會(huì)接收到通知并被自動(dòng)更新启上。

觀察者模式有以下角色:

  • 抽象被觀察者:將所有已注冊(cè)的觀察者對(duì)象保存在一個(gè)集合中。
  • 具體被觀察者:當(dāng)內(nèi)部狀態(tài)發(fā)生變化時(shí)店印,將會(huì)通知所有已注冊(cè)的觀察者冈在。
  • 抽象觀察者:定義了一個(gè)更新接口,當(dāng)被觀察者狀態(tài)改變時(shí)更新自己按摘。
  • 具體被觀察者:實(shí)現(xiàn)抽象觀察者的更新接口包券。
簡(jiǎn)單示例

1、抽象觀察者

public interface observer {
    
    public void update(String message);
}

2炫贤、具體觀察者

public class WeXinUser implements observer {
    private String name;
    
    public WeXinUser(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String message) {
        ...
    }
}

3溅固、抽象被觀察者

public interface observable {
    
    public void addWeXinUser(WeXinUser weXinUser);
    
    public void removeWeXinUser(WeXinUser weXinUser);
    
    public void notify(String message);
}

4、具體被觀察者

public class Subscription implements observable {
    private List<WeXinUser> mUserList = new ArrayList();
    
    @Override
    public void addWeXinUser(WeXinUser weXinUser) {
        mUserList.add(weXinUser);
    }
    
    @Override
    public void removeWeXinUser(WeXinUser weXinUser) {
        mUserList.remove(weXinUser);
    }
    
    @Override
    public void notify(String message) {
        for(WeXinUser weXinUser : mUserList) {
            weXinUser.update(message);
        }
    }
}

5兰珍、使用

Subscription subscription = new Subscription();

WeXinUser hongYang = new WeXinUser("HongYang");
WeXinUser rengYuGang = new WeXinUser("RengYuGang");
WeXinUser liuWangShu = new WeXinUser("LiuWangShu");

subscription.addWeiXinUser(hongYang);
subscription.addWeiXinUser(rengYuGang);
subscription.addWeiXinUser(liuWangShu);
subscription.notify("New article coming");
  • 實(shí)現(xiàn)了觀察者和被觀察者之間的抽象耦合侍郭,容易擴(kuò)展。
  • 有利于建立一套觸發(fā)機(jī)制掠河。
  • 一個(gè)被觀察者卡頓亮元,會(huì)影響整體的執(zhí)行效率。采用異步機(jī)制可解決此類問(wèn)題唠摹。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爆捞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勾拉,更是在濱河造成了極大的恐慌煮甥,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件望艺,死亡現(xiàn)場(chǎng)離奇詭異苛秕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)找默,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門艇劫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惩激,你說(shuō)我怎么就攤上這事店煞。” “怎么了风钻?”我有些...
    開(kāi)封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵顷蟀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我骡技,道長(zhǎng)鸣个,這世上最難降的妖魔是什么羞反? 我笑而不...
    開(kāi)封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮囤萤,結(jié)果婚禮上昼窗,老公的妹妹穿的比我還像新娘。我一直安慰自己涛舍,他們只是感情好澄惊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著富雅,像睡著了一般掸驱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上没佑,一...
    開(kāi)封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天毕贼,我揣著相機(jī)與錄音,去河邊找鬼图筹。 笑死帅刀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的远剩。 我是一名探鬼主播扣溺,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓜晤!你這毒婦竟也來(lái)了锥余?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤痢掠,失蹤者是張志新(化名)和其女友劉穎驱犹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體足画,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雄驹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淹辞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片医舆。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖象缀,靈堂內(nèi)的尸體忽然破棺而出蔬将,到底是詐尸還是另有隱情,我是刑警寧澤央星,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布霞怀,位于F島的核電站,受9級(jí)特大地震影響莉给,放射性物質(zhì)發(fā)生泄漏毙石。R本人自食惡果不足惜廉沮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望徐矩。 院中可真熱鬧废封,春花似錦、人聲如沸丧蘸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)力喷。三九已至,卻和暖如春演训,著一層夾襖步出監(jiān)牢的瞬間弟孟,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工样悟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拂募,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓窟她,卻偏偏與公主長(zhǎng)得像陈症,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子震糖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這里是對(duì)《設(shè)計(jì)模式Java版》[https://gof.quanke.name]的提煉匯總录肯,在真正深入理解之前,方...
    LeonXtp閱讀 1,005評(píng)論 0 0
  • 創(chuàng)建型模式 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一吊说。這種類型的設(shè)...
    隔墻送來(lái)秋千影閱讀 2,670評(píng)論 0 11
  • 創(chuàng)建型模式 工廠模式 工廠模式(Factory Pattern)是 Java 中最常用的設(shè)計(jì)模式之一论咏。這種類型的設(shè)...
    liuyang7519閱讀 327評(píng)論 0 2
  • 0.提前說(shuō)明 模式選擇的方法1)模式的功能——看是否能解決問(wèn)題2)模式的本質(zhì)——看模式是否主要用來(lái)解決這類問(wèn)題3)...
    王偵閱讀 1,054評(píng)論 0 1
  • 日子就在吵吵鬧鬧磕磕絆絆中過(guò)著,賀小妹大學(xué)畢業(yè)參加工作颁井,已經(jīng)要結(jié)婚了厅贪。這可是大事,老賀夫妻倆都嚴(yán)陣以待雅宾! 首先就是...
    油油的悠悠閱讀 652評(píng)論 0 0