java設(shè)計模式

1.單例模式

  • 作用
    保證在java應(yīng)用程序中盹沈,一個類Class只有一個實例存在星澳。
  • 優(yōu)點
    1.由于單例模式在內(nèi)存中只有一個實例转质,減少了內(nèi)存開銷
    2.單例模式可以避免對資源的多重占用
    3.單例模式可以在系統(tǒng)設(shè)置全局的訪問點临庇,優(yōu)化和共享資源訪問。
  • 使用情況
    1.建立目錄荣月,數(shù)據(jù)庫連接的單線程操作。
    2.某個需要被頻繁訪問的實例對象梳毙。
    第一種形式
 public class Singleton {

    /* 持有私有靜態(tài)實例哺窄,防止被引用,此處賦值為null账锹,目的是實現(xiàn)延遲加載 */
    private static Singleton instance = null;

    /* 私有構(gòu)造方法萌业,防止被實例化 */
    private Singleton() {
    }

    /* 懶漢式:第一次調(diào)用時初始Singleton,以后就不用再生成了
    靜態(tài)方法牌废,創(chuàng)建實例 */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

但是這種方法存在一個問題咽白,當(dāng)對數(shù)據(jù)庫進(jìn)行頻繁的讀寫操作時,會發(fā)生嚴(yán)重的不同步問題鸟缕。
解決方式
給getInstance方法加個鎖唄晶框!在這里我們可以使用synchronized關(guān)鍵字可以同步方法和同步代碼塊排抬,所以:

 public static synchronized Singleton getInstance() {  

           if (instance == null) {  
                   instance = new Singleton();  
               }  
             return instance;  
 } 

或者

public static Singleton getInstance() {  

     synchronized (Singleton.class) {  
         if (instance == null) {  
             instance = new Singleton();  
         }  
     }  
     return instance;  
 } 

建議使用第二種方式,對代碼段加鎖授段。這樣可以減少線程阻塞時間蹲蒲。

2.Factory(工廠模式)

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪一個類侵贵。工廠方法使一個類的實例化延遲到子類届搁,對同一個接口的管理類進(jìn)行管理和實例化創(chuàng)建。
假設(shè)需求如下:
動物Animal窍育,它有行為move()卡睦。有兩個實現(xiàn)類cat和dog。為了統(tǒng)一管理和創(chuàng)建我們設(shè)計一個工廠模式漱抓。   同時兩個子類有各自的行為表锻,Cat有eatFish(),Dog有eatBone().

Animal接口

interface animal {
    void move();
}

Cat類:

public class Cat implements Animal{

    @Override
    public void move() {
        // TODO Auto-generated method stub
        System.out.println("我是只肥貓乞娄,不愛動");
    }
    public void eatFish() {  
        System.out.println("愛吃魚");
    } 
}

Dog類:

public class Dog implements Animal{

    @Override
    public void move() {
        // TODO Auto-generated method stub
        System.out.println("我是狗瞬逊,跑的快");
    }
    public void eatBone() {  
        System.out.println("愛吃骨頭");
    } 
}

工廠類

public class Factory {

    //靜態(tài)工廠方法
    //多處調(diào)用,不需要實例工廠類 
     public static Cat produceCat() {  
            return new Cat();  
        } 
     public static Dog produceDog() {  
            return new Dog();  
        }
//當(dāng)然也可以一個方法仪或,通過傳入?yún)?shù)确镊,switch實現(xiàn)
}

使用:

Animal cat = Factory.produceCat();
cat.move();
//-----------------------------
Dog dog = Factory.produceDog();
dog.move();
dog.eatBone();
  • 作用
    工廠模式在業(yè)界運(yùn)用十分廣泛,如果都用new來生成對象范删,隨著項目的擴(kuò)展蕾域,animal還可以生出許多其他兒子來,當(dāng)然兒子還有兒子瓶逃,同時也避免不了對以前代碼的修改(比如加入后來生出兒子的實例),怎么管理束铭,想著就是一團(tuán)糟。

Animal cat = Factory.produceCat();
 這里實例化了Animal但不涉及到Animal的具體子類(減少了它們之間的偶合聯(lián)系性)厢绝,達(dá)到封裝效果契沫,也就減少錯誤修改的機(jī)會。

Java面向?qū)ο蟮脑瓌t昔汉,封裝(Encapsulation)和分派(Delegation)告訴我們:具體事情做得越多懈万,越容易范錯誤,

一般來說靶病,這樣的普通工廠就可以滿足基本需求会通。但是我們?nèi)绻略鲆粋€Animal的實現(xiàn)類panda,那么必然要在工廠類里新增了一個生產(chǎn)panda的方法娄周。就違背了 閉包的設(shè)計原則(對擴(kuò)展要開放對修改要關(guān)閉) 涕侈,于是有了抽象工廠模式。

2.1Abstract Factory(抽象工廠)

抽象工廠模式提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口煤辨,而無需指定它們具體的類裳涛。   啥意思木张?就是把生產(chǎn)抽象成一個接口,每個實例類都對應(yīng)一個工廠類(普通工廠只有一個工廠類)端三,同時所有工廠類都繼承這個生產(chǎn)接口舷礼。

生產(chǎn)接口Provider:

interface Provider {
    Animal produce(); 
}

每個產(chǎn)品都有自己的工廠類

public class CatFactory implements Provider{

    @Override
    public Animal produce() {
        // TODO Auto-generated method stub
        return new Cat();
    }
}

public class DogFactory implements Provider{

    @Override
    public Animal produce() {
        // TODO Auto-generated method stub
        return new Dog();
    }
}

產(chǎn)品生產(chǎn)

Provider provider = new CatFactory();
Animal cat =provider.produce();
cat.move();

現(xiàn)在我們要加入panda,直接新建一個pandaFactory就行了郊闯,這樣我們系統(tǒng)就非常靈活妻献,具備了動態(tài)擴(kuò)展功能。

2.2android中的Factory

例如AsyncTack的抽象工廠的實現(xiàn):

工廠的抽象:

59 public interface ThreadFactory {
//省略為備注
69    Thread newThread(Runnable r);
70 }

產(chǎn)品的抽象(new Runnable就是其實現(xiàn)類):

56   public interface Runnable {
//省略為備注
68    public abstract void run();
69 }

AsyncTask中工廠類的實現(xiàn):

185    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
186        private final AtomicInteger mCount = new AtomicInteger(1);
187
188        public Thread newThread(Runnable r) {
189            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
190        }
191    };

3.適配器模式团赁。

我們經(jīng)常要遇到要將兩個沒有關(guān)系類組合類一起使用腰鬼,第一個方案是修改兩個類的接口角撞。第二種方法就是我們要講到的adapter诚纸。

模式中的角色
需要適配的類(Adaptee):需要適配的類
適配器(Adapter):通過包裝一個需要適配的對象孝赫,把原接口轉(zhuǎn)換成目標(biāo)接口臊泌。
目標(biāo)接口:客戶所期待的接口匠楚,可以是具體抽象的類画机,也可以是接口盛卡。
// 需要適配的類

class Adaptee {  
    public void specificRequest() {  
        System.out.println("需要適配的類");  
    }  
}  
  
// 目標(biāo)接口  
interface Target {  
    public void request();  
} 

實現(xiàn)方式

// 適配器類實現(xiàn)標(biāo)準(zhǔn)接口
class Adapter implements Target{
    // 直接關(guān)聯(lián)被適配類
    private Adaptee adaptee;
    
    // 可以通過構(gòu)造函數(shù)傳入具體需要適配的被適配類對象
    public Adapter (Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    
    public void request() {
        // 這里是使用委托的方式完成特殊功能
        this.adaptee.specificRequest();
    }
}

// 測試類
public class Client {
    public static void main(String[] args) {
        // 需要先創(chuàng)建一個被適配類的對象作為參數(shù)
        Target adapter = new Adapter(new Adaptee());
        adapter.request();
    }
}

如果Target不是接口而是一個具體的類的情況矗钟,這里的Adapter直接繼承Target就可以了唆香。
如果Target和 Adaptee都是接口,并且都有實現(xiàn)類吨艇。 可以通過Adapter實現(xiàn)兩個接口來完成適配躬它。   還有一種叫PluggableAdapters,可以動態(tài)的獲取幾個adapters中一個。使用Reflection技術(shù)东涡,可以動態(tài)的發(fā)現(xiàn)類中的Public方法冯吓。

優(yōu)點
系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要疮跑。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用组贺。   將目標(biāo)類和適配者類解耦,通過引入一個適配器類重用現(xiàn)有的適配者類祖娘,而無需修改原有代碼失尖,更好的擴(kuò)展性。
缺點
過多的使用適配器渐苏,會讓系統(tǒng)非常零亂掀潮,不易整體進(jìn)行把握。比如琼富,明明看到調(diào)用的是A接口仪吧,其實內(nèi)部被適配成了B接口的實現(xiàn)。如果不是必要鞠眉,不要使用適配器薯鼠,而是直接對系統(tǒng)進(jìn)行重構(gòu)摄咆。

3.1Android的Adapter

android中的Adapter就有很多了,這個大家都經(jīng)常用人断。   Adapter是AdapterView視圖與數(shù)據(jù)之間的橋梁吭从,Adapter提供對數(shù)據(jù)的訪問,也負(fù)責(zé)為每一項數(shù)據(jù)產(chǎn)生一個對應(yīng)的View恶迈。


BaseAdapter
BaseAdapter

BaseAdapter的部分源碼:

30public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
31    private final DataSetObservable mDataSetObservable = new DataSetObservable();
32
33    public boolean hasStableIds() {
34        return false;
35    }
36    
37    public void registerDataSetObserver(DataSetObserver observer) {
38        mDataSetObservable.registerObserver(observer);
39    }
40
41    public void unregisterDataSetObserver(DataSetObserver observer) {
42        mDataSetObservable.unregisterObserver(observer);
43    }

4.責(zé)任鏈模式

使多個對象都有機(jī)會處理請求涩金,從而避免請求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對象連成一條鏈暇仲,并沿著這條鏈傳遞該請求步做,直到有一個對象處理它為止。發(fā)出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求奈附,這使得系統(tǒng)可以在不受客戶影響的情況下動態(tài)的重新組織和分配責(zé)任全度。

編程中小體現(xiàn):

if(a<10){
    ...
}
else if (a<20){
    ...
}
else if(a<30){
    ...
}
else{
    ...
}

程序必須依次掃描每個分支進(jìn)行判斷,找到對應(yīng)的分支處理斥滤。

責(zé)任鏈模式的優(yōu)點
可以降低系統(tǒng)的耦合度(請求者與處理者代碼分離)将鸵,簡化對象的相互連接,同時增強(qiáng)給對象指派職責(zé)的靈活性佑颇,增加新的請求方式處理類也很方便顶掉;
責(zé)任鏈模式的缺點
不能保證請求一定被接收,且由于比較長的責(zé)任鏈挑胸,請求的處理可能涉及到多個對象痒筒,系統(tǒng)性能將受到一定的影響,而且在進(jìn)行代碼調(diào)試時不太方便茬贵。每次都是從鏈頭開始簿透,這也正是鏈表的缺點。

4.1Android中的責(zé)任鏈模式

1解藻、dispatchTouchEvent作用:決定事件是否由onInterceptTouchEvent來攔截處理老充。
返回super.dispatchTouchEvent時,由onInterceptTouchEvent來決定事件的流向
返回false時舆逃,會繼續(xù)分發(fā)事件蚂维,自己內(nèi)部只處理了ACTION_DOWN
返回true時,不會繼續(xù)分發(fā)事件路狮,自己內(nèi)部處理了所有事件(ACTION_DOWN,ACTION_MOVE,ACTION_UP)

2虫啥、onInterceptTouchEvent作用:攔截事件,用來決定事件是否傳向子View
返回true時奄妨,攔截后交給自己的onTouchEvent處理
返回false時涂籽,交給子View來處理

3、onTouchEvent作用:事件最終到達(dá)這個方法
返回true時砸抛,內(nèi)部處理所有的事件评雌,換句話說树枫,后續(xù)事件將繼續(xù)傳遞給該view的onTouchEvent()處理
返回false時,事件會向上傳遞景东,由onToucEvent來接受砂轻,如果最上面View中的onTouchEvent也返回false的話,那么事件就會消失

1.如果ViewGroup找到了能夠處理該事件的View斤吐,則直接交給子View處理搔涝,自己的onTouchEvent不會被觸發(fā);
2.一個點擊事件產(chǎn)生后和措,它的傳遞過程如下:
Activity->Window->View庄呈。頂級View接收到事件之后,就會按相應(yīng)規(guī)則去分發(fā)事件派阱。如果一個View的onTouchEvent方法返回false诬留,那么將會交給父容器的onTouchEvent方法進(jìn)行處理,逐級往上贫母,如果所有的View都不處理該事件文兑,則交由Activity的onTouchEvent進(jìn)行處理“涠溃 
3.如果某一個View開始處理事件彩届,如果他不消耗ACTION_DOWN事件(也就是onTouchEvent返回false),則同一事件序列比如接下來進(jìn)行ACTION_MOVE誓酒,則不會再交給該View處理。
4.可以通過復(fù)寫onInterceptTouchEvent(ev)方法贮聂,攔截子View的事件(即return true)靠柑,把事件交給自己處理,則會執(zhí)行自己對應(yīng)的onTouchEvent方法吓懈。
5.子View可以通過調(diào)用getParent().requestDisallowInterceptTouchEvent(true); 阻止ViewGroup對其MOVE或者UP事件進(jìn)行攔截歼冰; 
6.ViewGroup默認(rèn)不攔截任何事件。
7.諸如TextView耻警、ImageView這些不作為容器的View隔嫡,一旦接受到事件,就調(diào)用onTouchEvent方法甘穿,它們本身沒有onInterceptTouchEvent方法腮恩。正常情況下,它們都會消耗事件(返回true)温兼,除非它們是不可點擊的(clickable和longClickable都為false)秸滴,那么就會交由父容器的onTouchEvent處理∧寂校 
8.點擊事件分發(fā)過程如下 dispatchTouchEvent—->OnTouchListener的onTouch方法—->onTouchEvent–>OnClickListener的onClick方法荡含。也就是說咒唆,我們平時調(diào)用的setOnClickListener,優(yōu)先級是最低的释液,所以全释,onTouchEvent或OnTouchListener的onTouch方法如果返回true,則不響應(yīng)onClick方法…

5.Observer(觀察者模式)

有時被稱作發(fā)布误债、訂閱模式恨溜,觀察者模式定義了一種一對多的依賴關(guān)系,讓多個觀察者對象同時監(jiān)聽某一主題對象找前,這個主題對象在狀態(tài)發(fā)生變化時糟袁,會通知所有的觀察者對象,使他們能夠自動更新自己躺盛。
將一個系統(tǒng)分割成一個一些類相互協(xié)作的類有一個不好的副作用项戴,那就是需要維護(hù)相關(guān)對象間的一致性。我們不希望為了維持一致性而使各類緊密耦合槽惫,這樣會給維護(hù)周叮、擴(kuò)展和重用都帶來不便。觀察者就是解決這類的耦合關(guān)系的(依賴關(guān)系并未完全解除界斜,抽象通知者依舊依賴抽象的觀察者)仿耽。

觀察者模組成
①抽象主題(Subject)

它把所有觀察者對象的引用保存到一個聚集里,每個主題都可以有任何數(shù)量的觀察者各薇。抽象主題提供一個接口项贺,可以增加和刪除觀察者對象。

②具體主題(ConcreteSubject)

將有關(guān)狀態(tài)存入具體觀察者對象峭判;在具體主題內(nèi)部狀態(tài)改變時开缎,給所有登記過的觀察者發(fā)出通知。

③抽象觀察者(Observer)

為所有的具體觀察者定義一個接口林螃,在得到主題通知時更新自己奕删。

④具體觀察者(ConcreteObserver)

實現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題狀態(tài)協(xié)調(diào)疗认。

言語蒼白完残,上代碼:

//抽象觀察者
public interface Observer
{
  public void update(String str);
    
}
//具體觀察者
public class ConcreteObserver implements Observer{
    @Override
    public void update(String str) {
        // TODO Auto-generated method stub
        System.out.println(str);
    }
}
//抽象主題
public interface Subject
{
    public void addObserver(Observer observer);
    public void removeObserver(Observer observer);
    public void notifyObservers(String str);
}
//具體主題
public class ConcreteSubject implements Subject{
    // 存放觀察者
    private List<Observer> list = new ArrayList<Observer>();
    @Override
    public void addObserver(Observer observer) {
        // TODO Auto-generated method stub
        list.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        // TODO Auto-generated method stub
        list.remove(observer);
    }

    @Override
    public void notifyObservers(String str) {
        // TODO Auto-generated method stub
        for(Observer observer:list){
            observer.update(str);
        }
    }
}

下面是測試類:

/**
 * @author fanrunqi
 */
public class Test {
     public static void main(String[] args) {
        //一個主題
         ConcreteSubject eatSubject = new ConcreteSubject();
         //兩個觀察者
         ConcreteObserver personOne = new ConcreteObserver();
         ConcreteObserver personTwo = new ConcreteObserver();
         //觀察者訂閱主題
         eatSubject.addObserver(personOne);
         eatSubject.addObserver(personTwo);
         
         //通知開飯了
         eatSubject.notifyObservers("開飯啦");
    }
}

“關(guān)于代碼你有什么想說的?” “沒有横漏,都在代碼里了” “(⊙o⊙)哦.....”

6.建造者模式

建造者模式:是將一個復(fù)雜的對象的構(gòu)建與它的表示分離(同構(gòu)建不同表示)谨设,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。

一個人活到70歲以上绊茧,都會經(jīng)歷這樣的幾個階段:嬰兒铝宵,少年,青年,中年鹏秋,老年尊蚁。并且每個人在各個階段肯定是不一樣的,世界上不存在兩個人在人生的這5個階段的生活完全一樣侣夷,但是活到70歲以上的人横朋,都經(jīng)歷了這幾個階段是肯定的。實際上這是一個比較經(jīng)典的建造者模式的例子了百拓。

將復(fù)雜的內(nèi)部創(chuàng)建封裝在內(nèi)部琴锭,對于外部調(diào)用的人來說,只需要傳入建造者和建造工具衙传,對于內(nèi)部是如何建造成成品的决帖,調(diào)用者無需關(guān)心。

建造者通常有以下角色:
① Builder:一個抽象接口蓖捶,用來規(guī)范產(chǎn)品對象的各個組成成分的建造地回。
② ConcreteBuilder:實現(xiàn)Builder接口,針對不同的商業(yè)邏輯俊鱼,具體化復(fù)雜對象的各部分的創(chuàng)建刻像,在建造過程完成后,提供產(chǎn)品的實例并闲。
③ Director:指導(dǎo)者细睡,調(diào)用具體建造者來創(chuàng)建復(fù)雜對象的各個部分,不涉及具體產(chǎn)品的信息帝火,只負(fù)責(zé)保證對象各部分完整創(chuàng)建或按某種順序創(chuàng)建溜徙。
④ Product:要創(chuàng)建的復(fù)雜對象。

與抽象工廠的區(qū)別:在建造者模式里购公,有個指導(dǎo)者萌京,由指導(dǎo)者來管理建造者,用戶是與指導(dǎo)者聯(lián)系的宏浩,指導(dǎo)者聯(lián)系建造者最后得到產(chǎn)品。即建造模式可以強(qiáng)制實行一種分步驟進(jìn)行的建造過程靠瞎。

Product和產(chǎn)品的部分Part接口

 public interface Product { }
 public interface Part { }
Builder:

 public interface Builder { 
    void buildPartOne(); 
    void buildPartTwo(); 
  
    Product getProduct(); 
  } 
ConcreteBuilder:

//具體建造工具
  public class ConcreteBuilder implements Builder { 
    Part partOne, partTwo; 

    public void buildPartOne() {
      //具體構(gòu)建代碼
    }; 
    public void buildPartTwo() { 
      //具體構(gòu)建代碼
    }; 
     public Product getProduct() { 
      //返回最后組裝的產(chǎn)品
    }; 
  }
Director :

 public class Director {
    private Builder builder; 
  
    public Director( Builder builder ) { 
      this.builder = builder; 
    } 
    public void construct() { 
      builder.buildPartOne();
      builder.buildPartTwo();
    } 
  } 

建造:

ConcreteBuilder builder = new ConcreteBuilder();
Director director = new Director(builder); 
//開始各部分建造 
director.construct(); 
Product product = builder.getResult();

優(yōu)點

客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié)比庄。

具體的建造者類之間是相互獨立的,對系統(tǒng)的擴(kuò)展非常有利乏盐。

由于具體的建造者是獨立的佳窑,因此可以對建造過程逐步細(xì)化,而不對其他的模塊產(chǎn)生任何影響

適用場合:
創(chuàng)建一些復(fù)雜的對象時父能,這些對象的內(nèi)部組成構(gòu)件間的建造順序是穩(wěn)定的神凑,但是對象的內(nèi)部組成構(gòu)件面臨著復(fù)雜的變化。

要創(chuàng)建的復(fù)雜對象的算法,獨立于該對象的組成部分溉委,也獨立于組成部分的裝配方法時鹃唯。

6.1Android中的Builder

android中的Dialog就使用了Builder Pattern,下面來看看AlertDialog的部分源碼瓣喊。

371    public static class Builder {
372        private final AlertController.AlertParams P;
373        private int mTheme;

393        public Builder(Context context, int theme) {
394            P = new AlertController.AlertParams(new ContextThemeWrapper(
395                    context, resolveDialogTheme(context, theme)));
396            mTheme = theme;
397        }

AlertDialog的Builder 是一個靜態(tài)內(nèi)部類坡慌,沒有定義Builder 的抽象接口。   對AlertDialog設(shè)置的屬性會保存在Build類的成員變量P(AlertController.AlertParams)中藻三。
Builder類中部分方法:

416        public Builder setTitle(int titleId) {
417            P.mTitle = P.mContext.getText(titleId);
418            return this;
419        }
452        public Builder setMessage(int messageId) {
453            P.mMessage = P.mContext.getText(messageId);
454            return this;
455        }
        
525        public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
526            P.mPositiveButtonText = text;
527            P.mPositiveButtonListener = listener;
528            return this;
529        }

而show()方法會返回一個結(jié)合上面設(shè)置的dialog實例

991        public AlertDialog show() {
992            AlertDialog dialog = create();
993            dialog.show();
994            return dialog;
995        }
996    }
997    
998}
972        public AlertDialog create() {
973            final AlertDialog dialog = new AlertDialog(P.mContext, mTheme, false);
974            P.apply(dialog.mAlert);
975            dialog.setCancelable(P.mCancelable);
976            if (P.mCancelable) {
977                dialog.setCanceledOnTouchOutside(true);
978            }
979            dialog.setOnCancelListener(P.mOnCancelListener);
980            dialog.setOnDismissListener(P.mOnDismissListener);
981            if (P.mOnKeyListener != null) {
982                dialog.setOnKeyListener(P.mOnKeyListener);
983            }
984            return dialog;
985        }

簡單建造:

new AlertDialog.Builder(context)
 .setTitle("標(biāo)題") 
 .setMessage("消息框")
 .setPositiveButton("確定", null)
 .show();

7.備忘錄模式

備忘錄模式又叫做快照模式(Snapshot Pattern)或Token模式洪橘,是對象的行為模式。
備忘錄對象是一個用來存儲另外一個對象內(nèi)部狀態(tài)的快照的對象棵帽。備忘錄模式的用意是在不破壞封裝的條件下熄求,將一個對象的狀態(tài)捕捉(Capture)住,并外部化逗概,存儲起來弟晚,從而可以在將來合適的時候把這個對象還原到存儲起來的狀態(tài)。備忘錄模式常常與命令模式和迭代子模式一同使用仗谆。

備忘錄模式所涉及的角色有三個:

① Originator(發(fā)起人): 負(fù)責(zé)創(chuàng)建一個備忘錄Memento指巡,用以記錄當(dāng)前時刻它的內(nèi)部狀態(tài),并可使用備忘錄恢復(fù)內(nèi)部狀態(tài)隶垮。Originator可根據(jù)需要決定Memento存儲Originator的哪些內(nèi)部狀態(tài)藻雪。

② Memento(備忘錄): 負(fù)責(zé)存儲Originnator對象的內(nèi)部狀態(tài),并可防止Originator以外的其他對象訪問備忘錄Memento狸吞,備忘錄有兩個接口勉耀,Caretaker只能看到備忘錄的窄接口,它只能將備忘錄傳遞給其他對象蹋偏。

③便斥、 Caretaker(管理者):負(fù)責(zé)保存好備忘錄Memento,不能對備忘錄的內(nèi)容進(jìn)行操作或檢查威始。

public class Originator {

    private String state;
    /**
     * 工廠方法枢纠,返回一個新的備忘錄對象
     */
    public Memento createMemento(){
        return new Memento(state);
    }
    /**
     * 將發(fā)起人恢復(fù)到備忘錄對象所記載的狀態(tài)
     */
    public void restoreMemento(Memento memento){
        this.state = memento.getState();
    }
    
    public String getState() {
        return state;
    }
    
    public void setState(String state) {
        this.state = state;
        System.out.println("當(dāng)前狀態(tài):" + this.state);
    }
    
}
public class Memento {
    
    private String state;
    
    public Memento(String state){
        this.state = state;
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
    }
    
}
public class Caretaker {

    private Memento memento;
    /**
     * 備忘錄的取值方法
     */
    public Memento retrieveMemento(){
        return this.memento;
    }
    /**
     * 備忘錄的賦值方法
     */
    public void saveMemento(Memento memento){
        this.memento = memento;
    }
}

使用:

Originator o = new Originator();
Caretaker c = new Caretaker();
//改變負(fù)責(zé)人對象的狀態(tài)
o.setState("On");
//創(chuàng)建備忘錄對象,并將發(fā)起人對象的狀態(tài)儲存起來
 c.saveMemento(o.createMemento());
//修改發(fā)起人的狀態(tài)
o.setState("Off");
//恢復(fù)發(fā)起人對象的狀態(tài)
 o.restoreMemento(c.retrieveMemento());

不需要了解對象的內(nèi)部結(jié)構(gòu)的情況下備份對象的狀態(tài)黎棠,方便以后恢復(fù)晋渺。

7.1Android中的Memento

Activity的onSaveInstanceState和onRestoreInstanceState就是通過Bundle(相當(dāng)于備忘錄對象)這種序列化的數(shù)據(jù)結(jié)構(gòu)來存儲Activity的狀態(tài),至于其中存儲的數(shù)據(jù)結(jié)構(gòu)脓斩,這兩個方法不用關(guān)心木西。

1365    protected void onSaveInstanceState(Bundle outState) {
1366        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
1367        Parcelable p = mFragments.saveAllState();
1368        if (p != null) {
1369            outState.putParcelable(FRAGMENTS_TAG, p);
1370        }
1371        getApplication().dispatchActivitySaveInstanceState(this, outState);
1372    }
1019    protected void onRestoreInstanceState(Bundle savedInstanceState) {
1020        if (mWindow != null) {
1021            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
1022            if (windowState != null) {
1023                mWindow.restoreHierarchyState(windowState);
1024            }
1025        }
1026    }

8. Prototype(原型模式)

原型模式,能快速克隆出一個與已經(jīng)存在對象類似的另外一個我們想要的新對象随静。   工作原理是:通過將一個原型對象傳給那個要發(fā)動創(chuàng)建的對象八千,這個要發(fā)動創(chuàng)建的對象通過請求原型對象拷貝它們自己來實施創(chuàng)建。

分為深拷貝和淺拷貝。深拷貝就是把對象里面的引用的對象也要拷貝一份新的對象恋捆,并將這個新的引用對象作為拷貝的對象引用(多讀兩遍)照皆。

一般使用原型模式有個明顯的特點,就是實現(xiàn)cloneable的clone()方法鸠信。

在Intent源碼中:

4084    @Override
4085    public Object clone() {
4086        return new Intent(this);
4087    }

這里Intent通過實現(xiàn)Cloneable接口來實現(xiàn)原型拷貝纵寝。

9. Strategy(策略模式)      定義:有一系列的算法,將每個算法封裝起來(每個算法可以封裝到不同的類中)星立,各個算法之間可以替換爽茴,策略模式讓算法獨立于使用它的客戶而獨立變化。

舉例:   一個影碟機(jī)绰垂,你往里面插什么碟子室奏,就能放出什么電影。   屬性動畫劲装,設(shè)置不同的插值器對象胧沫,就可以得到不同的變化曲線。   返回值解析占业,傳入什么樣的解析器绒怨,就可以把二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成什么格式的數(shù)據(jù),比如String谦疾、Json南蹂、XML。

策略模式其實就是多態(tài)的一個淋漓精致的體現(xiàn)念恍。

在android中不同Animation動畫的實現(xiàn)六剥,主要是依靠Interpolator的不同而實現(xiàn)的。

401     public void setInterpolator(Interpolator i) {
402         mInterpolator = i;
403     }

10. Template(模板模式)

定義:定義一個操作中的算法框架峰伙,而將一些步驟延遲到子類中疗疟,使得子類可以不改變一個算法的結(jié)構(gòu)即可重定義該算法的某些特定的步驟。      實現(xiàn)流程已經(jīng)確定瞳氓,實現(xiàn)細(xì)節(jié)由子類完成策彤。      生命周期對于我們都不陌生,它就是典型的Template模式匣摘,在具體流程確定的情況下锅锨,至于我們要復(fù)寫生命周期那些方法,實現(xiàn)那些功能由繼承activity的子類去具體實現(xiàn)恋沃。

關(guān)鍵在于必須有具體的執(zhí)行流程,比如AsyncTask必指。

11.proxy(代理模式)

定義:為其他對象提供一種代理以控制對這個對象的訪問囊咏。   代理: 在出發(fā)點到目的地之間有一道中間層。

應(yīng)用:Android跨進(jìn)程通信方式 ,建議去了解一下Binder機(jī)制梅割。

12. Interpreter(解釋器模式)

定義語言的文法霜第,并且建立一個解釋器來解釋該語言中的句子。

比如Android中通過PackageManagerService來解析AndroidManifest.xml中定義的Activity户辞、service等屬性泌类。

13. State(狀態(tài)模式)

行為是由狀態(tài)來決定的,不同狀態(tài)下有不同行為底燎。

注意:狀態(tài)模式的行為是平行的刃榨、不可替換的,策略模式的行為是彼此獨立可相互替換的双仍。

體現(xiàn):不同的狀態(tài)執(zhí)行不同的行為枢希,當(dāng)WIFI開啟時,自動掃描周圍的接入點朱沃,然后以列表的形式展示苞轿;當(dāng)wifi關(guān)閉時則清空。

14. Command(命令模式)

我們有很多命令逗物,把它們放在一個下拉菜單中搬卒,用戶通過先選擇菜單再選擇具體命令,這就是Command模式翎卓。

本來用戶(調(diào)用者)是直接調(diào)用這些命令的契邀,在菜單上打開文檔,就直接指向打開文檔的代碼莲祸,使用Command模式蹂安,就是在這兩者之間增加一個中間者,將這種直接關(guān)系拗?jǐn)嗳裰模瑫r兩者之間都隔離,基本沒有關(guān)系了田盈。      顯然這樣做的好處是符合封裝的特性,降低耦合度缴阎,有利于代碼的健壯性 可維護(hù)性 還有復(fù)用性允瞧。Command是將對行為進(jìn)行封裝的典型模式,F(xiàn)actory是將創(chuàng)建進(jìn)行封裝的模式蛮拔。

android底層邏輯對事件的轉(zhuǎn)發(fā)處理就用到了Command模式述暂。

15. Iterator(迭代模式)

提供一種方法順序訪問一個容器對象中的各個元素,而不需要暴露該對象的內(nèi)部表示建炫。

應(yīng)用:

在Java中的Iterator類畦韭。

Android中的 Cursor。

cursor.moveToFirst();

16. Composite(組合模式)

將對象以樹形結(jié)構(gòu)組織起來肛跌,以達(dá)成“部分-整體” 的層次結(jié)構(gòu)艺配,使得客戶端對單個對象和組合對象的使用具有一致性察郁。

Android中View的結(jié)構(gòu)是樹形結(jié)構(gòu),每個ViewGroup包含一系列的View转唉,而ViewGroup本身又是View皮钠。這是Android中非常典型的組合模式。

17. Flyweight(共享模式/享元模式)

定義:避免大量擁有相同內(nèi)容的小類的開銷(如耗費內(nèi)存)赠法,使大家共享一個類(元類)麦轰。

面向?qū)ο笳Z言的原則就是一切都是對象,但是如果真正使用起來砖织,有時對象數(shù)可能顯得很龐大款侵,比如,字處理軟件镶苞,如果以每個文字都作為一個對象喳坠,幾千個字,對象數(shù)就是幾千茂蚓,無疑耗費內(nèi)存壕鹉,那么我們還是要"求同存異",找出這些對象群的共同點聋涨,設(shè)計一個元類晾浴,封裝可以被共享的類,另外牍白,還有一些特性是取決于應(yīng)用(context)脊凰,是不可共享的,這也Flyweight中兩個重要概念內(nèi)部狀態(tài)intrinsic和外部狀態(tài)extrinsic之分茂腥。

說白點狸涌,就是先捏一個的原始模型,然后隨著不同場合和環(huán)境最岗,再產(chǎn)生各具特征的具體模型帕胆,很顯然,在這里需要產(chǎn)生不同的新對象般渡,所以Flyweight模式中常出現(xiàn)Factory模式懒豹。Flyweight的內(nèi)部狀態(tài)是用來共享的,F(xiàn)lyweight factory負(fù)責(zé)維護(hù)一個Flyweight pool(模式池)來存放內(nèi)部狀態(tài)的對象驯用。

Flyweight模式是一個提高程序效率和性能的模式脸秽,會大大加快程序的運(yùn)行速度。應(yīng)用場合很多:比如你要從一個數(shù)據(jù)庫中讀取一系列字符串蝴乔,這些字符串中有許多是重復(fù)的记餐,那么我們可以將這些字符串儲存在Flyweight池(pool)中。

在Android線程通信中薇正,每次獲取Message時調(diào)Message.obtain()其實就是從消息池中取出可重復(fù)使用的消息剥扣,避免產(chǎn)生大量的Message對象巩剖。

對于設(shè)計模式?jīng)]有必要去記憶,知道就好钠怯,說白了設(shè)計模式只是一種處理問題的方法,在遇到具體的問題時曙聂,可能會使用一些技巧晦炊,而這個技巧有可能是幾個模式結(jié)合,都只是運(yùn)用而已宁脊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末断国,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子榆苞,更是在濱河造成了極大的恐慌稳衬,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,496評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坐漏,死亡現(xiàn)場離奇詭異薄疚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)赊琳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評論 3 385
  • 文/潘曉璐 我一進(jìn)店門街夭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躏筏,你說我怎么就攤上這事板丽。” “怎么了趁尼?”我有些...
    開封第一講書人閱讀 157,091評論 0 348
  • 文/不壞的土叔 我叫張陵埃碱,是天一觀的道長。 經(jīng)常有香客問我酥泞,道長砚殿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,458評論 1 283
  • 正文 為了忘掉前任婶博,我火速辦了婚禮瓮具,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凡人。我一直安慰自己名党,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,542評論 6 385
  • 文/花漫 我一把揭開白布挠轴。 她就那樣靜靜地躺著传睹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪岸晦。 梳的紋絲不亂的頭發(fā)上欧啤,一...
    開封第一講書人閱讀 49,802評論 1 290
  • 那天睛藻,我揣著相機(jī)與錄音,去河邊找鬼邢隧。 笑死店印,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的倒慧。 我是一名探鬼主播按摘,決...
    沈念sama閱讀 38,945評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼纫谅!你這毒婦竟也來了炫贤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,709評論 0 266
  • 序言:老撾萬榮一對情侶失蹤付秕,失蹤者是張志新(化名)和其女友劉穎兰珍,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體询吴,經(jīng)...
    沈念sama閱讀 44,158評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡掠河,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,502評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了汰寓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片口柳。...
    茶點故事閱讀 38,637評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖有滑,靈堂內(nèi)的尸體忽然破棺而出跃闹,到底是詐尸還是另有隱情,我是刑警寧澤毛好,帶...
    沈念sama閱讀 34,300評論 4 329
  • 正文 年R本政府宣布望艺,位于F島的核電站,受9級特大地震影響肌访,放射性物質(zhì)發(fā)生泄漏找默。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,911評論 3 313
  • 文/蒙蒙 一吼驶、第九天 我趴在偏房一處隱蔽的房頂上張望惩激。 院中可真熱鬧,春花似錦蟹演、人聲如沸风钻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骡技。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間布朦,已是汗流浹背囤萤。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留是趴,地道東北人涛舍。 一個月前我還...
    沈念sama閱讀 46,344評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像右遭,于是被迫代替她去往敵國和親做盅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,500評論 2 348

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