Android進(jìn)階之光——設(shè)計模式(設(shè)計模式的分類、創(chuàng)建型設(shè)計模式)

設(shè)計模式六大原則

  • 單一職責(zé)原則:就一個類而言注盈,應(yīng)該僅有一個引起它變化的原因
  • 開放封閉原則:類、模塊叙赚、函數(shù)等應(yīng)該是可以拓展的老客,在拓展時盡量少修改
  • 里氏替換原則:所有引用基類的地方必須能透明地使用其子類對象
  • 依賴倒置原則:高層模塊不應(yīng)該依賴底層模塊僚饭,兩者都應(yīng)該依賴于抽象,抽象不應(yīng)該依賴于細(xì)節(jié)胧砰,細(xì)節(jié)應(yīng)該依賴于抽象
  • 迪米特原則:一個軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互左右
  • 接口隔離原則:一個類對另一個類的依賴應(yīng)該建立在最小的接口上

設(shè)計模式分類

  • 創(chuàng)建型:單例浪慌、工廠方法、抽象工廠朴则、建造者权纤、原型
  • 結(jié)構(gòu)設(shè)計型模式:適配器模式、裝飾模式乌妒、代理模式汹想、外觀模式、橋接模式撤蚊、組合模式古掏、享元模式
  • 行為型設(shè)計模式:策略模式、模板方法模式侦啸、觀察者模式槽唾、迭代器模式、責(zé)任鏈模式光涂、命令模式庞萍、備忘錄模式、狀態(tài)模式忘闻、訪問者模式钝计、中介者模式、解釋器模式

創(chuàng)建型設(shè)計模式

單例模式

  • 定義:保證一個類有且只有一個實(shí)例齐佳,并提供一個訪問的全局訪問點(diǎn)


    單例模式的通用結(jié)構(gòu)圖

單例模式的6種寫法

  • 餓漢模式
/**
 * 單例模式 
 * 餓漢模式
 */
class SingletonHungry{
    private static SingletonHungry instance = new SingletonHungry();
    private SingletonHungry(){}
    public static SingletonHungry getInstance(){
        return instance;
    }
}

這種方式在類加載時就完成了初始化私恬,所以類加載比較慢。但是這種方式基于類加載機(jī)制炼吴,避免了多線程同步問題本鸣。在類加載的時候就完成實(shí)例化,沒有達(dá)到懶加載的效果硅蹦。會造成內(nèi)存的浪費(fèi)

  • 懶漢模式(線程不安全)
class SingletonLazyNoSafe(){
    private static SingletonLazyNoSafe instance;

    private SingletonLazyNoSafe() {
        
    }

    public static SingletonLazyNoSafe getInstance() {
        if (instance == null) {
            instance = new SingletonLazyNoSafe();
        }
        return instance;
    }
}

懶漢式聲明了一個靜態(tài)對象荣德,在用戶第一次調(diào)用時初始化,節(jié)約了資源提针,但第一次加載時需要實(shí)例化命爬。而且在存在線程安全問題

  • 懶漢模式(線程安全|雙重檢查模式DCL)
class SingletonLazySafe {
    private static SingletonLazySafe instance = null;
    private SingletonLazySafe(){}

    public static SingletonLazySafe getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                instance = new SingletonLazySafe();
                }
            }
        }
        return instance;
    }
}

這種寫法在getInstance種對Singleton實(shí)例進(jìn)行了兩次判空:第一次是為了不必要的同步第二次是在Singleton等于null的時候才創(chuàng)建實(shí)例。這里使用volatile會或多或少地影響性能辐脖。DCL的優(yōu)點(diǎn)是資源利用率高,效率高皆愉。缺點(diǎn)是第一次加載時反應(yīng)慢嗜价,DCL在某些情況下會出現(xiàn)失效的問題艇抠,也就是DCL失效。

  • 靜態(tài)內(nèi)部類單例模式
class SingletonInner {
    private static SingletonInner instance = null;
    private SingletonInner() {
        
    }

    public static SingletonInner getInstance() {
        return SingletonInner.Holder.holderInstance;
    }

    private static class Holder {
        public static SingletonInner holderInstance = new SingletonInner();
          }
}

第一次加載Singleton類時并不會初始化holderInstance,只有第一次調(diào)用getInstance方法時虛擬機(jī)加載SingletonHolder并初始化holderInstance久锥,因此比較推薦使用靜態(tài)內(nèi)部類的單例模式

  • 枚舉單例

enum SingletonEnum {
    INSTANCE;
    public void someMethod() {
    }
}

單例模式的使用場景

  • 整個項(xiàng)目需要一個共享訪問點(diǎn)或共享數(shù)據(jù)
  • 創(chuàng)建一個對象需要耗費(fèi)的資源過多家淤,比如IO等
  • 工具類

簡單工廠模式

簡單工廠模式(靜態(tài)工廠方法模式)

  • 定義:由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例


    結(jié)構(gòu)圖

    簡單工廠模式種有如下角色:

  • Factory:工廠類,簡單工廠模式的核心瑟由,它負(fù)責(zé)實(shí)現(xiàn)所有實(shí)例的內(nèi)部邏輯絮重。工廠類創(chuàng)建的產(chǎn)品類的方法可以被外界直接調(diào)用,創(chuàng)建所需的產(chǎn)品對象
  • IProduct:抽象的產(chǎn)品類歹苦,簡單工廠模式所創(chuàng)建的所有對象的父類青伤,負(fù)責(zé)描述所有實(shí)例所有共有的公共接口
  • Product:具體產(chǎn)品類

簡單工廠模式的實(shí)現(xiàn)

假設(shè)有一個計算機(jī)的代工生產(chǎn)商,它目前已經(jīng)可以代工生產(chǎn)聯(lián)想計算機(jī)了殴瘦。隨著業(yè)務(wù)的拓展狠角,這個代工生產(chǎn)商還要生產(chǎn)惠普和華碩的計算機(jī)。 這樣我們就需要用一個單獨(dú)的類來專門生產(chǎn)計算機(jī)蚪腋,這就用到了簡單工廠模式丰歌。

/**
 * 簡單工廠模式
 */
public class SimpleFactoryType {
    public static void main(String[] args) {
        ComputerFactory.createComputer("hp").start();
    }
}

/**
 * 抽象產(chǎn)品類
 */
abstract class Computer {
    /**
     * 產(chǎn)品抽象方法,啟動計算機(jī)
     */
    abstract void start();
}

/**
 * 具體產(chǎn)品類
 */
class LenvooComputer extends Computer {

    @Override
    void start() {
        System.out.println("lenovo start");
    }
}

class HPComputer extends Computer {

    @Override
    void start() {
        System.out.println("HP start");
    }
}

class ASUSComputer extends Computer {

    @Override
    void start() {
        System.out.println("ASUS start");
    }
}

class ComputerFactory {
    public static Computer createComputer(String type) {
        Computer mComputer = null;
        switch (type) {
            case "lenovo":
                mComputer = new LenvooComputer();
                break;
            case "hp":
                mComputer = new HPComputer();
                break;
            case "asus":
                mComputer = new ASUSComputer();
                break;
        }
        return mComputer;
    }
}

簡單工廠模式的使用場景

  • 工廠類負(fù)責(zé)創(chuàng)建的對象比較少
  • 客戶只需要知道傳入工廠類的參數(shù)屉凯,無須關(guān)心創(chuàng)建邏輯

優(yōu)點(diǎn)

用戶可以根據(jù)參數(shù)獲得對應(yīng)的類實(shí)例立帖。避免直接實(shí)例化類,降低了耦合性

缺點(diǎn)

可實(shí)例化的類型在編譯期間就已經(jīng)被確定悠砚。如果增加新類型厘惦,則需要修改工廠,違背了開放封閉原則哩簿。簡單工廠需要知道所有的要生產(chǎn)的類型

工廠方法模式

  • 定義 定義一個用于創(chuàng)建對象的接口宵蕉,讓子類決定實(shí)例化哪個類。工廠方法使一個類的實(shí)例化延遲到其子類


    image.png

在工廠方法模式種有如下角色:

  • Product:抽象產(chǎn)品類
  • ConcreteProduct:具體產(chǎn)品類
  • Factory:抽象工廠類节榜,返回抽象產(chǎn)品對象
  • ConcreteFactory:具體工廠類羡玛,返回具體產(chǎn)品實(shí)例
/**
 * 工廠方法模式
 */
public class FactoryMethodType {
    public static void main(String[] args) {
        GDComputerFactor computerFactor = new GDComputerFactor();
        computerFactor.createComputerABS(HPComputerABS.class).start();
    }
}
/**
 * 抽象產(chǎn)品類
 */
abstract class ComputerABS {
    /**
     * 產(chǎn)品抽象方法,啟動計算機(jī)
     */
    abstract void start();
}
/**
 * 具體產(chǎn)品類
 */
class LenvooComputerABS extends ComputerABS {

    @Override
    void start() {
        System.out.println("lenovo start");
    }
}

class HPComputerABS extends ComputerABS {

    @Override
    void start() {
        System.out.println("HP start");
    }
}

class ASUSComputerABS extends ComputerABS {

    @Override
    void start() {
        System.out.println("ASUS start");
    }
}

/**
 * 抽象工廠宗苍,返回抽象的產(chǎn)品
 */
abstract class  ComputerFactoryABS{
    public abstract <T extends ComputerABS> T createComputerABS(Class<T> cls);
}

class GDComputerFactor extends ComputerFactoryABS {

    @Override
    public <T extends ComputerABS> T createComputerABS(Class<T> cls) {
        ComputerABS computerABS = null;
        String clsName = cls.getName();
        try {
            computerABS = ((ComputerABS) Class.forName(clsName).newInstance());
        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) computerABS;
    }
}

建造者模式

建造者模式也被稱為生成器模式稼稿,它是創(chuàng)建一個復(fù)雜對象的創(chuàng)建型模式,其將構(gòu)建復(fù)雜對象的過程和它的部件解耦讳窟。使得構(gòu)建過程和部件表示分離開來让歼。例如我們要 DIY 一臺臺式計
算機(jī)。 我們找到 DIY 商家丽啡。這時我們可以要求這臺計算機(jī)的 CPU谋右、 主板或者其他部件都是什么牌子的、 什么配置的补箍,這些部件是我們可以根據(jù)自己的需求來變化的改执。 但是這些部件組裝成計算機(jī)的過程是一樣的啸蜜,我們無須知道這些部件是怎樣組裝成計算機(jī)的,我們只需要提供相關(guān)部件的牌子和配置就可以了辈挂。對于這種情況我們就可以采用建造者模式衬横,將部件和組裝過程分離,使得構(gòu)建過程和部件都可以自由拓展终蒂,兩者之間的耦合也降到最低蜂林。

  • 定義:將一個復(fù)雜對象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示


    結(jié)構(gòu)圖

    在建造者模式種有如下角色:

  • Director:導(dǎo)演類
  • Builder:抽象Builder類拇泣,規(guī)范產(chǎn)品的組建噪叙,一般由子類實(shí)現(xiàn)
  • ConcreteBuilder:具體建造者,實(shí)現(xiàn)Builder類定義的所有方法挫酿,返回組建好的對象
  • Product:產(chǎn)品類

建造者模式的簡單實(shí)現(xiàn)

public class BuilderTypeLSN {
    public static void main(String[] args) {
        ApplePhoneBuilder phoneBuilder = new ApplePhoneBuilder();
        Director director = new Director(phoneBuilder);
        Phone phone = director.createPhone("aaa", "b", "c");
    }
}

class Phone {
    private String mCPU;
    private String 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;
    }
}

abstract class Builder{
    abstract void buildCPU(String cpuName);

    abstract void buildMainboard(String boardName);

    abstract void buildRam(String ram);

    abstract Phone createPhone();
}

class ApplePhoneBuilder extends Builder {
    Phone phone = new Phone();
    @Override
    void buildCPU(String cpuName) {
        phone.setmCPU(cpuName);
    }

    @Override
    void buildMainboard(String boardName) {
        phone.setmMainboard(boardName);
    }

    @Override
    void buildRam(String ram) {
        phone.setmRam(ram);
    }

    @Override
    Phone createPhone() {
        return phone;
    }
}

class Director {
    Builder mBuilder = null;

    public Director(Builder mBuilder) {
        this.mBuilder = mBuilder;
    }

    public Phone createPhone(String cpu, String board, String ram) {
        mBuilder.buildCPU(cpu);
        mBuilder.buildMainboard(board);
        mBuilder.buildRam(ram);
        return mBuilder.createPhone();
    }
    
}

使用建造者的場景和優(yōu)缺點(diǎn)

  • 使用場景
    • 當(dāng)創(chuàng)建復(fù)雜對象的算法應(yīng)該獨(dú)立于該對象的組成部分以及它們的裝配方式時构眯。
    • 相同的方法,不同的執(zhí)行順序早龟,產(chǎn)生不同的事件結(jié)果時惫霸。
    • 多個部件或零件都可以被裝配到一個對象中,但是產(chǎn)生的運(yùn)行結(jié)果又不相同時葱弟。
    • 產(chǎn)品類非常復(fù)雜壹店,或者產(chǎn)品類中的調(diào)用順序不同而產(chǎn)生了不同的效能。
    • 在創(chuàng)建一些復(fù)雜的對象時芝加,這些對象的內(nèi)部組成構(gòu)件間的建造順序是穩(wěn)定的硅卢,但是對象的內(nèi)部組成構(gòu)件面臨著復(fù)雜的變化。
  • 優(yōu)點(diǎn):
    • 使用建造者模式可以使客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)藏杖。
    • 具體的建造者類之間是相互獨(dú)立的将塑,容易擴(kuò)展。
    • 由于具體的建造者是獨(dú)立的蝌麸,因此可以對建造過程逐步細(xì)化点寥,而不對其他的模塊產(chǎn)生任何影響。
  • 缺點(diǎn): 產(chǎn)生多余的 Build 對象以及導(dǎo)演類
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末来吩,一起剝皮案震驚了整個濱河市敢辩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弟疆,老刑警劉巖戚长,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異怠苔,居然都是意外死亡同廉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恤溶,“玉大人乓诽,你說我怎么就攤上這事帜羊≈涑蹋” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵讼育,是天一觀的道長帐姻。 經(jīng)常有香客問我,道長奶段,這世上最難降的妖魔是什么饥瓷? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮痹籍,結(jié)果婚禮上呢铆,老公的妹妹穿的比我還像新娘。我一直安慰自己蹲缠,他們只是感情好棺克,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著线定,像睡著了一般娜谊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斤讥,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天纱皆,我揣著相機(jī)與錄音,去河邊找鬼芭商。 笑死派草,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铛楣。 我是一名探鬼主播近迁,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蛉艾!你這毒婦竟也來了钳踊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤勿侯,失蹤者是張志新(化名)和其女友劉穎拓瞪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體助琐,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡祭埂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛆橡。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡舌界,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泰演,到底是詐尸還是另有隱情呻拌,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布睦焕,位于F島的核電站藐握,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏垃喊。R本人自食惡果不足惜猾普,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望本谜。 院中可真熱鬧初家,春花似錦、人聲如沸乌助。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽眷茁。三九已至炕泳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間上祈,已是汗流浹背培遵。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留登刺,地道東北人籽腕。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像纸俭,于是被迫代替她去往敵國和親皇耗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

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