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

設(shè)計(jì)模式(適用場(chǎng)景 優(yōu)點(diǎn))

從Android代碼中來(lái)記憶23種設(shè)計(jì)模式

單例模式

確保單例類只有一個(gè)實(shí)例喜每,并且這個(gè)單例類提供一個(gè)函數(shù)接口讓其他類獲取到這個(gè)唯一的實(shí)例戏锹。

什么時(shí)候需要使用單例模式呢:如果某個(gè)類躯泰,創(chuàng)建時(shí)需要消耗很多資源毁枯,即new出這個(gè)類的代價(jià)很大;或者是這個(gè)類占用很多內(nèi)存,如果創(chuàng)建太多這個(gè)類實(shí)例會(huì)導(dǎo)致內(nèi)存占用太多。

//此為懶漢式 餓漢式在聲明時(shí)直接初始化
public class Singleton{
    //volatile保證了其他線程拿到的也是最新的實(shí)例
    private volatile static Singleton instance;
    //將默認(rèn)的構(gòu)造函數(shù)私有化摩疑,防止其他類手動(dòng)new
    private Singleton(){};
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance==null){
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

為什么需要2次判斷是否為空呢危融?第一次判斷是為了避免不必要的同步畏铆,第二次判斷是確保在此之前沒(méi)有其他線程進(jìn)入到sychronized塊創(chuàng)建了新實(shí)例。
使用類級(jí)內(nèi)部類吉殃,只有內(nèi)部類被調(diào)用到(即Singleton.singleton)才會(huì)裝載

public class MySingleton {  
    /** 
     * 類級(jí)的內(nèi)部類辞居,也就是靜態(tài)的成員式內(nèi)部類,該內(nèi)部類的實(shí)例與外部類的實(shí)例 
     * 沒(méi)有綁定的關(guān)系蛋勺,而且只有被調(diào)用到才會(huì)裝載瓦灶,從而實(shí)現(xiàn)了延遲加載 
     */  
    private static class Singleton{  
        /** 
         * 靜態(tài)初始化器,用JVM來(lái)保證線程安全 
         */  
        private static MySingleton singleton = new MySingleton();  
          
        static {  
            System.out.println("---->類級(jí)的內(nèi)部類被加載");  
        }  
        private Singleton(){  
            System.out.println("---->類級(jí)的內(nèi)部類構(gòu)造函數(shù)被調(diào)用");  
        }  
    }  
    //私有化構(gòu)造函數(shù)  
    private MySingleton(){  
        System.out.println("-->開(kāi)始調(diào)用構(gòu)造函數(shù)");  
    }  

    public static MySingleton getInstance(){  
        System.out.println("-->開(kāi)始調(diào)用公有方法返回實(shí)例");  
        System.out.println("-->返回單例");  
        return Singleton.singleton;
    }  
}  

記憶:getSystemService的內(nèi)部實(shí)現(xiàn)

建造者模式(Builder)

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

主要是在創(chuàng)建某個(gè)對(duì)象時(shí),需要設(shè)定很多的參數(shù)(通過(guò)setter方法)巧娱,但是這些參數(shù)必須按照某個(gè)順序設(shè)定碉怔,或者是設(shè)置步驟不同會(huì)得到不同結(jié)果(模式不同后續(xù)的可用屬性也有不同)

記憶:在創(chuàng)建對(duì)話框時(shí)的代碼

身邊例子:通過(guò)方法構(gòu)建一個(gè)頁(yè)面,有無(wú)list,有無(wú)tab,有無(wú)column,每一個(gè)先導(dǎo)選擇都會(huì)導(dǎo)致后續(xù)使用參數(shù)的不同

工廠方法模式

定義一個(gè)創(chuàng)建對(duì)象的接口禁添,讓子類決定實(shí)例化哪個(gè)類
其實(shí)撮胧,在getSystemService方法中就是用到了工廠模式,他就是根據(jù)傳入的參數(shù)決定創(chuàng)建哪個(gè)對(duì)象老翘,當(dāng)然了芹啥,由于返回的都是以單例模式存在的對(duì)象,因此不用new了铺峭,直接把單例返回就好墓怀。

抽象工廠模式

為創(chuàng)建一組相關(guān)或者是相互依賴的對(duì)象提供一個(gè)接口,而不需要制定他們的具體類 (滿足依賴倒置原則)

public abstract class AbstractProductA{//標(biāo)題欄
    public abstract void method();
}
public abstract class AbstractProdectB{//無(wú)數(shù)據(jù)
    public abstract void method();
}
public abstract class AbstractFactory{//listTemplate
    public abstract AbstractProductA createProductA();

    public abstract AbstractProductB createProductB();
}
public  class ConcreteFactory1 extends AbstractFactory{//listT實(shí)例1
    public  AbstractProductA createProductA(){
        return new ConcreteProductA1();
    }
    public  AbstractProductB createProductB(){
        return new ConcreteProductB1();
    }
}
public  class ConcreteFactory2 extends AbstractFactory{//listT實(shí)例2
    public  AbstractProductA createProductA(){
        return new ConcreteProductA2();
    }

    public  AbstractProductB createProductB(){
        return new ConcreteProductB2();
    }
}

策略模式

定義:有一系列的算法卫键,將每個(gè)算法封裝起來(lái)(每個(gè)算法可以封裝到不同的類中)傀履,各個(gè)算法之間可以替換,策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化永罚。
其中在屬性動(dòng)畫(huà)中使用時(shí)間插值器的時(shí)候就用到了啤呼。在使用動(dòng)畫(huà)時(shí)卧秘,你可以選擇線性插值器、加速減速插值器官扣、減速插值器以及自定義的插值器翅敌。這些插值器都是實(shí)現(xiàn)根據(jù)時(shí)間流逝的百分比來(lái)計(jì)算出當(dāng)前屬性值改變的百分比。通過(guò)根據(jù)需要選擇不同的插值器惕蹄,實(shí)現(xiàn)不同的動(dòng)畫(huà)效果蚯涮。

使用者可能會(huì)覺(jué)得有工廠方法的影子,因?yàn)樯衔闹刑岬降?strong>線性插值器卖陵、加速減速插值器遭顶、減速插值器以及自定義的插值器,很明顯可以通過(guò)工廠方法構(gòu)建出來(lái)泪蔫,但是策略模式是代表了將每個(gè)算法封裝起來(lái)(每個(gè)算法可以封裝到不同的類中)棒旗,各個(gè)算法之間可以替換,策略模式讓算法獨(dú)立于使用它的客戶而獨(dú)立變化撩荣,側(cè)重點(diǎn)不同铣揉。所以我們要知道,同時(shí)使用多種設(shè)計(jì)模式是很常見(jiàn)的餐曹。
身邊的例子:生成申請(qǐng)類的工廠方法逛拱,只需要一個(gè)變量的改變,如果申請(qǐng)類內(nèi)部存在算法台猴,則應(yīng)用了策略模式朽合。可以說(shuō)工廠方法可以作為策略模式的實(shí)現(xiàn)方式饱狂,但他不是唯一的
反例:使用了建造者模式的工廠方法

適配器模式

定義:把一個(gè)類的接口變換成客戶端所期待的另一個(gè)接口曹步,從而使原本因接口不匹配而無(wú)法在一起工作的兩個(gè)類能夠在一起工作。
比較典型的有ListView和RecyclerView的adapter嗡官。為什么ListView需要使用適配器呢箭窜?主要是,ListView(view)只關(guān)心它的每個(gè)ItemView衍腥,而不關(guān)心這個(gè)ItemView具體顯示的是什么磺樱。而我們的數(shù)據(jù)源(model)存放的是要顯示的內(nèi)容,它保存了每一個(gè)ItemView要顯示的內(nèi)容婆咸。ListView和數(shù)據(jù)源之間沒(méi)有任何關(guān)系竹捉,這時(shí)候,需要通過(guò)適配器(adapter)尚骄,適配器提供getView方法給ListView使用块差,每次ListView只需提供位置信息給getView函數(shù),然后getView函數(shù)根據(jù)位置信息向數(shù)據(jù)源獲取對(duì)應(yīng)的數(shù)據(jù),根據(jù)數(shù)據(jù)返回不同的View憨闰。

觀察者模式

定義:定義了對(duì)象之間的一對(duì)多的關(guān)系状蜗,其實(shí)就是1對(duì)n,當(dāng)“1”發(fā)生變化時(shí)鹉动,“n”全部得到通知轧坎,并更新
觀察者模式一個(gè)比較經(jīng)典的應(yīng)用就是:訂閱——發(fā)布系統(tǒng)泽示。很容易理解缸血,發(fā)布消息時(shí),將消息發(fā)送給每個(gè)訂閱者械筛。
那么Android哪里用到了觀察者模式呢捎泻?我們看看ListView的適配器,有個(gè)函數(shù)notifyDataSetChanged()函數(shù)埋哟,這個(gè)函數(shù)其實(shí)就是通知ListView的每個(gè)Item笆豁,數(shù)據(jù)源發(fā)生了變化,請(qǐng)各位Item重新刷新一下定欧。

觀察者模式的實(shí)現(xiàn)

//抽象主題
public interface MySubject {
    void registerObserver(MyObserver o);
    void removeObserver(MyObserver o);
    void notifyObserver();
}
//抽象觀察者
public interface MyObserver {
    void update(String authorName, String articleName);
}
//實(shí)現(xiàn)主題
public class WeChatServer implements MySubject {

    private List<MyObserver> myObservers;
    private String authorName;
    private String articleName;

    public WeChatServer(String authorName) {
        myObservers = new ArrayList<>();
        this.authorName = authorName;
    }

    public void publishArticle(String articleName) {
        this.articleName = articleName;
        notifyObserver();
    }

    @Override
    public void registerObserver(MyObserver o) {
        myObservers.add(o);
    }

    @Override
    public void removeObserver(MyObserver o) {
        if (myObservers.contains(o)) {
            myObservers.remove(o);
        }
    }

    @Override
    public void notifyObserver() {
        myObservers.forEach(item -> {
            item.update(authorName, articleName);
        });
    }
}
//具體的觀察者
public class WeChatClient implements MyObserver {
    private String username;
    public WeChatClient(String username) {
        this.username = username;
    }

    @Override
    public void update(String authorName, String articleName) {
        System.out.println(username + ": " + authorName + " 發(fā)了一篇文章 " + articleName);
    }
}
public class Main {
    public static void main(String[] args) {
        WeChatServer weChatServer = new WeChatServer("Java識(shí)堂");
        WeChatClient user1 = new WeChatClient("張三");
        WeChatClient user2 = new WeChatClient("李四");
        weChatServer.registerObserver(user1);
        weChatServer.registerObserver(user2);
        weChatServer.publishArticle("《五分鐘學(xué)會(huì)觀察者模式》");
    }
}

裝飾模式

動(dòng)態(tài)的給一個(gè)對(duì)象添加額外的職責(zé)渔呵,就增加功能來(lái)說(shuō)怒竿,裝飾模式比子類繼承的方式更靈活砍鸠。
通過(guò)簡(jiǎn)單代碼來(lái)理解裝飾模式:

public abstract class Component{
    public abstract void operate();
}

public class ConcreteComponent extends Component{
    public void operate(){
        //具體的實(shí)現(xiàn)
    }
}

public class Decorator{
    private Component component;
    public Decorator(Component component){
        this.component=component;
    }
    public void operate(){
        operateA();
        component.operate();
        operateB();
    }
    public void operateA(){
        //具體操作
    }
    public void operateB(){
        //具體操作
    }
}

那么在Android哪里出現(xiàn)了裝飾模式呢?我們平時(shí)經(jīng)常用到Context類耕驰,但是其實(shí)Context類只是個(gè)抽象類爷辱,具體實(shí)現(xiàn)是ContextImpl,那么誰(shuí)是ContextImpl的裝飾類呢朦肘?我們知道Activity是個(gè)Context,但是Activity 并不是繼承于Context,而是繼承于ContextThremeWrapper.而ContextThremeWrapper繼承于ContextWrapper,ContextWrapper繼承Context.說(shuō)了這么多饭弓,跟裝飾模式有啥關(guān)系?主要是引入ContextWrapper這個(gè)類媒抠。ContextWrapper內(nèi)部有個(gè)Context引用mContext弟断,并且ContextWrapper中對(duì)Context的每個(gè)方法都有實(shí)現(xiàn),在實(shí)現(xiàn)中調(diào)用的就是mContext相同的方法趴生。

身邊的例子:BaseActivity+MyBaseActivity(通過(guò)抽象類+實(shí)現(xiàn)類的組合實(shí)現(xiàn)職責(zé)添加)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末阀趴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苍匆,更是在濱河造成了極大的恐慌刘急,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浸踩,死亡現(xiàn)場(chǎng)離奇詭異叔汁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門据块,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)码邻,“玉大人,你說(shuō)我怎么就攤上這事另假∶疤玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵浪谴,是天一觀的道長(zhǎng)开睡。 經(jīng)常有香客問(wèn)我,道長(zhǎng)苟耻,這世上最難降的妖魔是什么篇恒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮凶杖,結(jié)果婚禮上胁艰,老公的妹妹穿的比我還像新娘。我一直安慰自己智蝠,他們只是感情好腾么,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著杈湾,像睡著了一般解虱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上漆撞,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天殴泰,我揣著相機(jī)與錄音,去河邊找鬼浮驳。 笑死悍汛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的至会。 我是一名探鬼主播离咐,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奉件!你這毒婦竟也來(lái)了宵蛀?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瓶蚂,失蹤者是張志新(化名)和其女友劉穎糖埋,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體窃这,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞳别,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年征候,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祟敛。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疤坝,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出馆铁,到底是詐尸還是另有隱情跑揉,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布埠巨,位于F島的核電站历谍,受9級(jí)特大地震影響辣垒,放射性物質(zhì)發(fā)生泄漏望侈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一勋桶、第九天 我趴在偏房一處隱蔽的房頂上張望脱衙。 院中可真熱鬧,春花似錦例驹、人聲如沸捐韩。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)荤胁。三九已至,卻和暖如春仪召,著一層夾襖步出監(jiān)牢的瞬間寨蹋,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工扔茅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秸苗。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓召娜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親惊楼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子玖瘸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

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