22.《Android源碼設(shè)計(jì)模式解析與實(shí)戰(zhàn)》筆記

一柳骄、面向?qū)ο蟮牧笤瓌t
單一職責(zé)Single Responsibility Principle突琳,縮寫SRP拓售。定義:對(duì)一個(gè)類而言晕窑,應(yīng)該僅有一個(gè)引起它變化的原因玄呛。簡(jiǎn)單來說置吓,一個(gè)類中應(yīng)該是一組相關(guān)性很高的函數(shù)菱阵。

開閉原則Open Close Principle乳蓄,縮寫OCP他爸。定義:軟件中的對(duì)象(類聂宾、模塊、函數(shù)等)應(yīng)該對(duì)于擴(kuò)展是開放的诊笤,對(duì)于修改是封裝的系谐。

里氏替換Liskov Substitution Principle,縮寫LSP讨跟。定義:所有引用基類的地方必須能透明地使用其子類的對(duì)象纪他。

依賴倒置Dependence Inversion Principle,縮寫DIP晾匠。定義:模塊間的依賴通過抽象發(fā)生茶袒,實(shí)現(xiàn)類之間不發(fā)生直接的依賴關(guān)系,其依賴關(guān)系是通過接口或抽象類產(chǎn)生的凉馆。

接口隔離原則Interface Segregation Principle薪寓,縮寫ISP。定義:客戶端不應(yīng)該依賴它不需要的接口澜共。另一種定義是:類間的依賴關(guān)系應(yīng)該建立在最小的接口上向叉。

迪米特原則Law of Demeter,縮寫LOD咳胃,也稱最少知識(shí)原則(Least Knowledge Principle)植康。定義:一個(gè)對(duì)象應(yīng)該對(duì)其他對(duì)象有最少的了解。

  • 設(shè)計(jì)模式分類:
    • 創(chuàng)建型:Singleton展懈、Builder销睁、Prototype、Factory Method存崖、Abstract Factory
    • 結(jié)構(gòu)型:Proxy冻记、Composite、Adapter来惧、Decorator冗栗、Flyweight、Facade、Bridge
    • 行為:Strategy隅居、State钠至、Chain of Responsibility、Interpreter胎源、Command棉钧、Observer、Memento涕蚤、Iterator宪卿、Template Method、Visitor万栅、Mediator

二佑钾、應(yīng)用最廣的模式——單例模式
定義:確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例烦粒。

使用場(chǎng)景:比如創(chuàng)建一個(gè)對(duì)象需要消耗的資源過多休溶。

關(guān)鍵點(diǎn):構(gòu)造函數(shù)不對(duì)外開放,一般為Private撒遣;通過一個(gè)靜態(tài)方法或者枚舉返回單例類對(duì)象邮偎;確保單例類的對(duì)象有且只有一個(gè),尤其是在多線程環(huán)境下义黎;確保單例類對(duì)象在反序列化時(shí)不會(huì)重新構(gòu)建對(duì)象禾进。

簡(jiǎn)單示例:公司人員構(gòu)成,單個(gè)CEO

實(shí)現(xiàn)方式
懶漢模式:聲明一個(gè)靜態(tài)對(duì)象廉涕,并且在用戶第一次調(diào)用getInstance時(shí)進(jìn)行初始化泻云,而上述餓漢模式(CEO類)是在聲明麥太太對(duì)象時(shí)就已經(jīng)初始化。
Double Check Lock(DCL)實(shí)現(xiàn)單例:

      public static Singleton getInstance() {
        if (mInstance == null) {
          synchronized  (Singleton.class) {
            if (mInstance == null) {
              sInstance = new Singleton();
            }
          }
        }
        return sInstance;
      }

靜態(tài)內(nèi)部類單例模式:

      public static Singleton getInstance() {
        return SingletonHolder.sInstance;
      }
      private static class SingletonHolder{
        priveate static final Singleton sInstance = new Singleton();
      }

枚舉單例:

public enum SingletonEnum {
        INSTANCE;
        public void doSomething() {
          System.out.println("do sth.");
        }
      }

使用容器實(shí)現(xiàn)單例模式:

 public class SingletonManager {
        prinvate static Map<String,Object> objMap = new HashMap<String,Object>();
      }

在Android源碼中:通常我們使用LayoutInflater.from(Context)來獲取LayoutInflater服務(wù)狐蜕,下面看看LayoutInflater.from(Context)的實(shí)現(xiàn)宠纯。

public static LayoutInflater from(Context context) {
  LayoutInflater layoutInflater = (LayoutInflater)context.getSystemServer(Context.LAYOUT_INFLATER_SERVICE);
  if(layoutInflater == null) {
    throw new AssertonError("LayoutInflater not found."):
  }
  return layoutInflater;
}

深入理解LayoutInflater

  • 小結(jié)
    • 優(yōu)點(diǎn):減少內(nèi)存開支;減少系統(tǒng)的性能開銷层释;避免對(duì)資源的多重占用婆瓜;在系統(tǒng)設(shè)置全局的訪問點(diǎn),優(yōu)化和共享資源訪問贡羔。
    • 缺點(diǎn):擴(kuò)展困難廉白;單例對(duì)象如果持有Context,容易引發(fā)內(nèi)存泄漏乖寒,傳遞給單例對(duì)象的Context最好是Application Context猴蹂。

三、自由擴(kuò)展你的項(xiàng)目——Builder模式
介紹:Builder模式是一步一步創(chuàng)建一個(gè)復(fù)雜對(duì)象的創(chuàng)建型模式楣嘁,它允許用戶在不知道內(nèi)部構(gòu)建細(xì)節(jié)的情況下磅轻,可以更精細(xì)地控制對(duì)象的構(gòu)造流程珍逸。該模式是為了將構(gòu)建復(fù)雜對(duì)象的過程和它的部件解耦,使得構(gòu)建過程和部件的表示隔離開來聋溜。

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

使用場(chǎng)景:相同的方法勤婚,不同的執(zhí)行順序摹量,產(chǎn)生不同的事件結(jié)果時(shí);多個(gè)部件或零件馒胆,都可以裝配到一個(gè)對(duì)象中,但是產(chǎn)生的運(yùn)行結(jié)果又不相同時(shí)凝果;產(chǎn)品類非常復(fù)雜祝迂,或者產(chǎn)品類中的調(diào)用順序不同產(chǎn)生了不同的什么用,這個(gè)時(shí)候使用建造者模式非常合適器净;當(dāng)初始化一個(gè)對(duì)象特別復(fù)雜型雳,如參數(shù)多,且很多參數(shù)都具有默認(rèn)值時(shí)山害。

UML類圖
Product——產(chǎn)品的抽象類纠俭。
Builder——抽象Builder類,規(guī)范產(chǎn)品的組建浪慌,一般是由子類實(shí)現(xiàn)具體的邪惡v地方過程冤荆;
ConcreteBuilder——具體的Builder類;
Director——統(tǒng)一組裝的過程权纤。

簡(jiǎn)單實(shí)現(xiàn)
計(jì)算機(jī)的組裝過程

在Android源碼中
在Android源碼中钓简,最常用到的Builder模式就是AlertDialog.Builder,使用該Builder來構(gòu)建復(fù)雜的AlertDialog對(duì)象汹想。

public class AlertDialog extends Dialog implements DialogInterface{
  private AlertContraller mAlert;
  public void setTitle(char Sequence title) { super...;mAlert.setTitle(title);}
  public static class Builder{
    private final AlertController.AlertParams p;
    public Builder setTitle(...) {
      p.mTitle = title; return this;
    }
    public AlertDialog create() {
      final AlertDialog dialog = new AlertDialog(p.mContext,mTheme,false);
      p.apply(dialog.mAlert);
      return dialog;
      }
  }
}

深入了解WindowManager

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):良好的封裝性外邓;建造者獨(dú)立,容易擴(kuò)展
缺點(diǎn):會(huì)產(chǎn)生多余的Builder對(duì)象以及Director對(duì)象古掏,消耗內(nèi)存损话。

四、使程序運(yùn)行更高效——原型模式
介紹:多用于創(chuàng)建復(fù)雜的或者構(gòu)造耗時(shí)的實(shí)例槽唾,在這種情況下丧枪,復(fù)制一個(gè)已經(jīng)存在的實(shí)例可使程序運(yùn)行更高效

定義:用原型實(shí)例指定創(chuàng)建對(duì)象的種類,并通過復(fù)制這些原型創(chuàng)建新的對(duì)象夏漱。

使用場(chǎng)景:1.類初始化需要消耗非常多的資源豪诲,通過原型復(fù)制避免這些消耗。2.通過new產(chǎn)生一個(gè)對(duì)象需要非常繁瑣的數(shù)據(jù)準(zhǔn)備或訪問權(quán)限挂绰,這時(shí)可以使用原型模式屎篱。3.一個(gè)對(duì)象需要提供給其他對(duì)象訪問服赎,而且各個(gè)調(diào)用者可能都需要修改其值時(shí),可以考慮使用原型模式復(fù)制多個(gè)對(duì)象供調(diào)用者使用交播,即保護(hù)性拷貝重虑。

UML類圖
Client:客戶端用戶。
Prototype:抽象類或者接口秦士,聲明具備clone能力缺厉。
ConcretePrototype:具體的原型類

簡(jiǎn)單實(shí)現(xiàn):文檔拷貝

淺拷貝和深拷貝:深拷貝對(duì)引用型的字段也采用拷貝的形式(也用上clone函數(shù)嘛)。

在Android源碼中:Intent

Intent的查找與匹配

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):原型模式是在內(nèi)存中二進(jìn)制流的拷貝隧土,要比直接new一個(gè)對(duì)象性能好很多提针,特別是要在一個(gè)循環(huán)內(nèi)產(chǎn)生大量的對(duì)象時(shí),原型模式可以更好地體現(xiàn)其優(yōu)點(diǎn)曹傀。
缺點(diǎn):減少了約束辐脖。

五、應(yīng)用最廣泛的模式——工廠方法模式
定義:定義一個(gè)用于創(chuàng)建對(duì)象的接口皆愉,讓子類決定實(shí)例化哪個(gè)類嗜价。

使用場(chǎng)景:在任何需要生成復(fù)雜對(duì)象的地方,都可以使用工廠方法模式幕庐。復(fù)雜對(duì)象適合使用工廠模式久锥,用new就可以完成創(chuàng)建的對(duì)象無需使用工廠模式。

UML類圖
Product:定義工廠方法所創(chuàng)建的對(duì)象的接口
ConcreteProduct:實(shí)現(xiàn)Product接口
Creator:聲明工廠方法异剥,該方法返回一個(gè)Product類型的對(duì)象瑟由;調(diào)用工廠方法以創(chuàng)建一個(gè)Product對(duì)象
ConcreteCreator:重定義工廠方法以返回一個(gè)ConcreteProduct實(shí)例

簡(jiǎn)單實(shí)現(xiàn):組裝汽車

    public <T extends AudiCar> T createAudiCar(Class<T> clz) {
      AudiCar car = null;
      try {
        car = (AudiCar) Class.forName(clz.getName()).newInstance();
      } catch (Exception e) {
        e.printStackTrace();
      }
      return (T) car;
    }

在Android源碼中:iterator

關(guān)于onCreate方法:對(duì)于一個(gè)app來說,入口在ActivityThread類中届吁。這是一個(gè)final類错妖,一個(gè)app對(duì)應(yīng)一個(gè)ActivityThread,當(dāng)Zygote進(jìn)程孵化出一個(gè)新的進(jìn)程后疚沐,會(huì)執(zhí)行ActivityThread的main方法暂氯,在main方法中做一些比較常規(guī)的邏輯,比如準(zhǔn)備Looper和消息隊(duì)列亮蛔,然后調(diào)用attach方法將其綁定到ActivityManagerService中痴施。

實(shí)戰(zhàn)

小結(jié)
缺點(diǎn):導(dǎo)致類結(jié)構(gòu)復(fù)雜化

六、創(chuàng)建型設(shè)計(jì)模式——抽象工廠模式
定義:為創(chuàng)建一組相關(guān)或者是相互依賴的對(duì)象提供一個(gè)接口究流,而不需要指定它們的具體類辣吃。

使用場(chǎng)景:一個(gè)對(duì)象族有相同的約束時(shí)可以使用抽象工廠模式。

UML類圖
AbstractFactory:抽象工廠角色芬探,它聲明了一組用于創(chuàng)建一種產(chǎn)品的方法神得,每一個(gè)方法對(duì)應(yīng)一種產(chǎn)品。
ConcreteFactory:具體工廠角色偷仿,它實(shí)現(xiàn)了在抽象工廠中定義的創(chuàng)建產(chǎn)品的方法哩簿,生成一組具體產(chǎn)品宵蕉,這些產(chǎn)品構(gòu)成了一個(gè)產(chǎn)品種類,每一個(gè)產(chǎn)品都位于某個(gè)產(chǎn)品等級(jí)結(jié)構(gòu)中节榜。
AbstractProduct:抽象產(chǎn)品種類羡玛,它為每種產(chǎn)品聲明接口。
ConcreteProduct:具體產(chǎn)品角色宗苍,它定義具體工廠生產(chǎn)的具體產(chǎn)品對(duì)象稼稿,實(shí)現(xiàn)抽象產(chǎn)品接口中聲明的業(yè)務(wù)方法。

簡(jiǎn)單實(shí)現(xiàn):汽車工廠生產(chǎn)部件

在Android源碼中:Android底層對(duì)MediaPlayer的創(chuàng)建讳窟。

在Android開發(fā)中的應(yīng)用:主題樹

小結(jié)
優(yōu)點(diǎn):分離接口與實(shí)現(xiàn)
缺點(diǎn):類文件的爆炸性增加让歼;不太容易擴(kuò)展新的產(chǎn)品類

七、時(shí)勢(shì)造英雄——策略模式
定義:策略模式定義了一系列的算法挪钓,并將每一個(gè)算法封裝起來是越,而且使它們還可以互相替換。

使用場(chǎng)景
針對(duì)同一類型問題的多種處理方法碌上,僅僅是具體行為有差別時(shí)
需要安全地封裝多種同一類型的操作時(shí)
出現(xiàn)同一抽象類有多個(gè)子類,而又需要使用if-else或者switch-case來選擇具體子類時(shí)

UML類圖
Context——用來操作策略的上下文環(huán)境
Stragety——策略的抽象
ConcreteStragetyA浦徊、ConcreteStragetyB——具體的策略實(shí)現(xiàn)

簡(jiǎn)單實(shí)現(xiàn):公共交通費(fèi)用計(jì)算

在Android源碼中:時(shí)間插值器

深入屬性動(dòng)畫

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):結(jié)構(gòu)清晰明了馏予、使用簡(jiǎn)單直觀;耦合度相對(duì)而言較低盔性,擴(kuò)展方便霞丧;操作封裝也更為徹底、數(shù)據(jù)更為安全
缺點(diǎn):隨著策略的增加冕香,子類也會(huì)變得繁多蛹尝。

八、隨遇而安——狀態(tài)模式
定義:當(dāng)一個(gè)對(duì)象的內(nèi)在狀態(tài)改變時(shí)允許改變其行為悉尾,這個(gè)對(duì)象看起來像是改變了其類突那。

使用場(chǎng)景:一個(gè)對(duì)象的行為取決于它的狀態(tài),并且它必須在運(yùn)行時(shí)根據(jù)狀態(tài)改變它的行為构眯;代碼中包含大量與對(duì)象狀態(tài)有關(guān)的條件語句愕难,例如,一個(gè)操作中含有龐大的多分支語句惫霸,且這些分支依賴于該對(duì)象的狀態(tài)猫缭;

UML類圖
Context:環(huán)境類,定義客戶感興趣的接口壹店,維護(hù)一個(gè)State子類的實(shí)例猜丹,這個(gè)實(shí)例定義了對(duì)象的當(dāng)前狀態(tài)。
State:抽象狀態(tài)類或者狀態(tài)接口硅卢,定義一個(gè)或者一組接口射窒,表示該狀態(tài)下的行為藏杖。
ConcreteStateA、ConcreteStateB:具體狀態(tài)類轮洋,每一個(gè)具體的狀態(tài)類實(shí)現(xiàn)抽象State中定義的接口制市,從而達(dá)到不同狀態(tài)下的不同行為。

簡(jiǎn)單示例:電視遙控器

狀態(tài)模式:WIFI管理

實(shí)戰(zhàn):登錄系統(tǒng)

小結(jié)
優(yōu)點(diǎn):State模式將所有與一個(gè)特定的狀態(tài)相關(guān)的行為都放入一個(gè)狀態(tài)對(duì)象中弊予,它提供了一個(gè)更好的方法來組織與特定狀態(tài)相關(guān)的代碼,將煩瑣的狀態(tài)判斷轉(zhuǎn)換成結(jié)構(gòu)清晰的狀態(tài)類族误褪,在避免代碼膨脹的同時(shí)也保證了可擴(kuò)展性與可維護(hù)性碾褂。
缺點(diǎn):增加系統(tǒng)類和對(duì)象的個(gè)數(shù)兽间。

九、使編程更有靈活性——責(zé)任鏈模式
定義:使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求正塌,從而避免了請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系嘀略。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求乓诽,直到有對(duì)象處理它為止帜羊。

使用場(chǎng)景:多個(gè)對(duì)象可以處理同一請(qǐng)求,但具體由哪個(gè)對(duì)象處理則在運(yùn)行時(shí)動(dòng)態(tài)決定鸠天;在請(qǐng)求處理者不明確的情況下向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求讼育;需要?jiǎng)討B(tài)指定一組對(duì)象處理請(qǐng)求。

UML類圖
Handler:抽象處理者角色稠集,聲明一個(gè)請(qǐng)求處理的方法奶段,并在其中保持一個(gè)對(duì)下一個(gè)處理節(jié)點(diǎn)Handler對(duì)象的引用。
ConcreteHandler:具體處理者角色剥纷,對(duì)請(qǐng)求進(jìn)行處理痹籍,如果不能處理則將該請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn)上的處理對(duì)象。

簡(jiǎn)單實(shí)現(xiàn):報(bào)銷費(fèi)用

在Android源碼中:ViewGroup中將事件派發(fā)到子View

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):對(duì)請(qǐng)求者和處理者關(guān)系解耦筷畦,提高代碼的靈活性词裤。
缺點(diǎn):對(duì)鏈中請(qǐng)求處理者的遍歷太多,會(huì)影響性能鳖宾。

十吼砂、化繁為簡(jiǎn)的翻譯機(jī)——解釋器模式
介紹:Interpreter Pattern是一種用得比較少的行為型模式,其提供了一種解釋語言的語法或表達(dá)式的方式周偎,該模式定義了一個(gè)表達(dá)式接口澳眷,通過該接口解釋一個(gè)特定的上下文钳踊。

定義: 給定一個(gè)語言,定義它的方法的一種表示祭埂,并定義一個(gè)解釋器,該解釋器使用該表示來解釋語言中的句子航罗。

使用場(chǎng)景:如果某個(gè)簡(jiǎn)單的語言需要解釋執(zhí)行而且可以將該語言中的語句表示為一個(gè)抽象語法樹時(shí)柏锄,可以考慮使用解釋器模式缭嫡;在某些特定的領(lǐng)域出現(xiàn)不斷重復(fù)的問題時(shí)妇蛀,可以將該領(lǐng)域的問題轉(zhuǎn)化為一種語法規(guī)則下的語句,然后構(gòu)建解釋器來解釋該語句纵诞。

UML類圖
AbstractExpression:抽象表達(dá)式
TerminalExpression:終結(jié)符表達(dá)式
NonterminalExpression:非終結(jié)符表達(dá)式
Context:上下文環(huán)境類
Client:客戶類

簡(jiǎn)單實(shí)現(xiàn):數(shù)學(xué)運(yùn)算

在Android源碼中:PackageParser

關(guān)于PackageManagerService

小結(jié)
優(yōu)點(diǎn):靈活的擴(kuò)展性
缺點(diǎn):生成大量的類,對(duì)于過于復(fù)雜的方法纸俭,構(gòu)建其抽象語法樹會(huì)顯得異常煩瑣揍很。

十一、讓程序暢通執(zhí)行——命令模式
定義:將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓用戶使用不同的請(qǐng)求把客戶端參數(shù)化北救;對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,以及支持可撤銷的操作攘宙。

使用場(chǎng)景:需要抽象出待執(zhí)行的動(dòng)作,然后以參數(shù)的形式提供出來——類似于過程設(shè)計(jì)中的回調(diào)機(jī)制铺韧,而命令模式正是回調(diào)機(jī)制的一個(gè)面向?qū)ο蟮奶娲贰?br> 在不同的時(shí)刻指定哈打、排列和執(zhí)行請(qǐng)求。一個(gè)命令對(duì)象可以有與初始請(qǐng)求無關(guān)的生存期罢维。
需要支持取消操作。
支持修改日志功能吓肋,這樣當(dāng)系統(tǒng)崩潰時(shí),這些修改可以被重做一遍均蜜。
需要支持事務(wù)操作。

UML類圖
Receiver:接收者角色
Command:命令角色
ConcreteCommand:具體命令角色
Invoker:請(qǐng)求者角色
Client:客戶端角色

簡(jiǎn)單實(shí)現(xiàn):俄羅斯方塊

在Android源碼中:在Android事件機(jī)制中底層連加對(duì)事件的轉(zhuǎn)發(fā)處理,Android的每一種事件在屏幕上產(chǎn)生后都會(huì)經(jīng)由底層邏輯將其轉(zhuǎn)換為一個(gè)NotifyArgs對(duì)象椎麦。

Android事件輸入系統(tǒng)介紹

命令模式實(shí)戰(zhàn)

十二段化、解決解耦的鑰匙——觀察者模式
介紹:觀察者模式是一個(gè)使用率非常高的模式,它最常用的地方是GUI系統(tǒng)佃延、訂閱——發(fā)布系統(tǒng)。

定義:定義對(duì)象間一種一對(duì)多的依賴關(guān)系坐桩,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài)膘螟,則所有依賴于它的對(duì)象都會(huì)得到通知并被自動(dòng)更新。

使用場(chǎng)景
關(guān)聯(lián)行為場(chǎng)景内斯,需要注意的是,關(guān)聯(lián)行為是可拆分的真朗,而不是“組合”關(guān)系此疹;
事件多級(jí)觸發(fā)場(chǎng)景;
跨系統(tǒng)的消息交換場(chǎng)景蜜猾,如消息隊(duì)列秀菱、事件總線的處理機(jī)制。

UML類圖
Subject:抽象主題題
ConcreteSubject:具體主題
Observer:抽象觀察者
ConcreteObserver:具體的觀察者

簡(jiǎn)單實(shí)現(xiàn):發(fā)布——訂閱過程

public class ObserverTest {

    public static class Coder implements Observer {
        public String name;
        
        public Coder(String name) {
            this.name = name;
        }
        
        @Override
        public void update(Observable o,Object args) {
            System.out.println("Hi, " + name + ",It's update: " + args);
        }
        
        @Override
        public String toString() {
            return "Coder: " + name;
        }
    }
    
    public static class DevTechFrontier extends Observable {
        public void postNewPublication(String content) {
            setChanged();
            notifyObservers(content);
        }
    }
    
    public static void main(String[] args) {
        DevTechFrontier devTechFrontier = new DevTechFrontier();
        
        Coder coder1 = new Coder("coder1");
        Coder coder2 = new Coder("coder2");
        Coder coder3 = new Coder("coder3");
        
        devTechFrontier.addObserver(coder1);
        devTechFrontier.addObserver(coder2);
        devTechFrontier.addObserver(coder3);
        
        devTechFrontier.postNewPublication("hahahahahahhhhahahahha");
    }
}

Observer和Observable是JDK中內(nèi)置類型蹭睡,Observer是抽象的觀察者角色,Coder是具體的觀察者角色祟昭;Observable是抽象的被觀察者角色,DevTechFrontier是具體的被觀察者角色疾忍。當(dāng)DevTechFrontier有更新時(shí)歧沪,會(huì)遍歷所有觀察者(這里是Coder)裕菠,然后給這些觀察者發(fā)布一個(gè)更新的消息平委,即調(diào)用Coder的update方法岗照,這樣就達(dá)到了一對(duì)多的通知功能熙宇。在這個(gè)過程中,通知系統(tǒng)都是依賴Observer和Observable這些抽象類诞吱,因此阿趁,對(duì)于Coder和DevTechFrontier完全沒有耦合蘑辑,保證了訂閱系統(tǒng)的靈活性副砍,可擴(kuò)展性谨垃。

在Android源碼中:ListView的Adapter

觀察者模式的深入拓展: BroadcastReceiver

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):觀察者和被觀察者之間是抽象耦合撼短,應(yīng)對(duì)業(yè)務(wù)變化;增強(qiáng)系統(tǒng)靈活性膀捷、可擴(kuò)展性
缺點(diǎn):執(zhí)行效率低

十三迈嘹、編程中的“后悔藥”——備忘錄模式
介紹:是一種行為模式,該模式用于保存對(duì)象當(dāng)前狀態(tài)全庸,并且在之后可以再次恢復(fù)到此狀態(tài)秀仲。

定義:在不破壞封閉的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài)壶笼,并在該對(duì)象之外保存這個(gè)狀態(tài)神僵,這樣,以后就可將該對(duì)象恢復(fù)到原先保存的狀態(tài)覆劈。

使用場(chǎng)景
需要保存一個(gè)對(duì)象在某一個(gè)時(shí)刻的狀態(tài)或部分狀態(tài)
如果用一個(gè)接口來讓其他對(duì)象得到這些狀態(tài)保礼,將會(huì)暴露對(duì)象的實(shí)現(xiàn)細(xì)節(jié)并破壞對(duì)象的封裝性,一個(gè)對(duì)象不希望外界直接訪問其內(nèi)部狀態(tài)责语,通過中間對(duì)象可以間接訪問其內(nèi)部狀態(tài)炮障。

UML類圖
Originator:負(fù)責(zé)創(chuàng)建一個(gè)備忘錄,可以記錄坤候、恢復(fù)自身的內(nèi)部狀態(tài)胁赢。
Memento:備忘錄角色,用于存儲(chǔ)Originator的內(nèi)部狀態(tài)白筹,并且可以子上Originator以外的對(duì)象訪問Memento智末。
Caretaker:負(fù)責(zé)存儲(chǔ)備忘錄,不能對(duì)備忘錄的內(nèi)容進(jìn)行操作和訪問徒河,只能將備忘錄傳遞給其他對(duì)象

簡(jiǎn)單示例:游戲存檔

在Android源碼中: Activity中的狀態(tài)保存系馆。

深度拓展

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):給用戶提供了一種可以恢復(fù)狀態(tài)的機(jī)制,可以使用戶能夠比較方便地回到某個(gè)歷史的狀態(tài)虚青;實(shí)現(xiàn)了信息的封裝它呀,使得用戶不需要關(guān)心狀態(tài)的保存細(xì)節(jié)。
缺點(diǎn):消耗資源

十四棒厘、解決問題的“第三者”——迭代器模式
定義:提供一種方法順序訪問一個(gè)容器對(duì)象中的各個(gè)元素纵穿,而又不需要暴露該對(duì)象的內(nèi)部表示。

使用場(chǎng)景:遍歷一個(gè)容器對(duì)象時(shí)

UML類圖
Iterator:迭代器接口
Concrete Iterator:具體迭代器類
Aggregate:容器接口
Concrete Aggregate:具體容器類
Client:客戶類

簡(jiǎn)單實(shí)現(xiàn):員工遍歷

在Android源碼中:數(shù)據(jù)庫查詢使用的Cursor

小結(jié)
優(yōu)點(diǎn):支持以不同的方式去遍歷一個(gè)容器對(duì)象
缺點(diǎn):類文件的增加

十五奢人、抓住問題核心——模板方法模式
定義:定義一個(gè)操作中的算法的框架谓媒,而將一些步驟延遲到子類中,使得子類可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟何乎。

使用場(chǎng)景
多個(gè)子類有公有的方法句惯,并且邏輯基本相同時(shí)土辩;
重要、復(fù)雜的算法抢野,可以把核心算法設(shè)計(jì)為模板方法拷淘,周邊的相關(guān)細(xì)節(jié)功能則由各個(gè)子類實(shí)現(xiàn)
重構(gòu)時(shí),模板方法模式是一個(gè)經(jīng)常使用的模式指孤,把相同的代碼抽取到父類中启涯,然后通過鉤子函數(shù)約束其行為

UML類圖
AbsTemplate:抽象類,定義了一套算法框架
ConcreteImplA:具體實(shí)現(xiàn)類A
ConcreteImplB:具體實(shí)現(xiàn)類B

簡(jiǎn)單示例:碼農(nóng)和軍事計(jì)算機(jī)開機(jī)

在Android源碼中:AsyncTask

嘗試拓展:Activity的生命周期函數(shù)

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):封裝不變部分恃轩,擴(kuò)展可變部分结洼;提取公共部分代碼,便于維護(hù)
缺點(diǎn):代碼閱讀難度提高

十六叉跛、訪問者模式
介紹:是一種將數(shù)據(jù)操作與數(shù)據(jù)結(jié)構(gòu)分享的設(shè)計(jì)模式松忍,是23種最復(fù)雜的一個(gè),但使用頻率并不高筷厘。

定義:封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作鸣峭,它可以在不改變這個(gè)數(shù)據(jù)結(jié)構(gòu)的前提下定義什么用于這些元素的新的操作。

使用場(chǎng)景
對(duì)象結(jié)構(gòu)比較穩(wěn)定敞掘,但經(jīng)常需要在此對(duì)象結(jié)構(gòu)上定義新的操作
需要對(duì)一個(gè)對(duì)象結(jié)構(gòu)中的對(duì)象進(jìn)行很多不同的并且不相關(guān)的操作叽掘,而需要避免這些操作“污染”這些對(duì)象的類,也不希望在增加新操作時(shí)修改這些類玖雁。

UML類圖
Visitor:接口或者抽象類更扁,它定義了對(duì)每一個(gè)元素訪問的行為
ConcreteVisitor:具體的訪問者,它需要給出對(duì)每一個(gè)元素類訪問時(shí)所產(chǎn)生的具體行為
Element:元素接口或者抽象類赫冬,它定義了一個(gè)接收訪問者(accept)的方法浓镜,其意義是指每一個(gè)元素都要可以被訪問者訪問
ElementA、ElementB:具體的元素類劲厌,它提供接受訪問方法的具體實(shí)現(xiàn)膛薛,而這個(gè)具體的實(shí)現(xiàn),通常情況下是使用訪問者提供的訪問該元素類的方法
ObjectStructure:定義當(dāng)中所提到的對(duì)象結(jié)構(gòu)补鼻,對(duì)象結(jié)構(gòu)是一個(gè)抽象表述哄啄,它內(nèi)部管理了元素集合,并且可以迭代這些元素供訪問者訪問

簡(jiǎn)單示例:老板风范、CTO對(duì)員工的訪問

在Android源碼中:編譯時(shí)注解

實(shí)戰(zhàn):實(shí)現(xiàn)APT

小結(jié)
優(yōu)點(diǎn):各角色職責(zé)分享咨跌,符合單一職責(zé)原則;具體優(yōu)秀的擴(kuò)展性硼婿;使得數(shù)據(jù)結(jié)構(gòu)和什么用于結(jié)構(gòu)上的操作解耦锌半,使得操作集合可以獨(dú)立變化;靈活性
缺點(diǎn):具體元素對(duì)訪問者公布細(xì)節(jié)寇漫,違反迪米特原則刊殉;具體元素變更時(shí)導(dǎo)致修改成本大殉摔;違反了依賴倒置原則,為了達(dá)到“區(qū)別對(duì)待”而依賴了具體類记焊,沒有依賴抽象

十七逸月、“和事佬”——中介者模式
定義:中介者模式包裝了一系列對(duì)象相互作用的方式,使得這些對(duì)象不必相互明顯作用

使用場(chǎng)景:當(dāng)對(duì)象之間的交互操作很多且每個(gè)對(duì)象的行為操作都依賴彼此時(shí)遍膜,為防止在修改一個(gè)對(duì)象的行為時(shí)彻采,同時(shí)涉及修改很多其他對(duì)象的行為。

UML類圖
Mediator:抽象中介者角色捌归,定義了同事對(duì)象到中介者對(duì)象的接口,一般以抽象類的方式實(shí)現(xiàn)
ConcreteMediator:具體中介者角色岭粤,繼承于抽象中介者惜索,實(shí)現(xiàn)了父類定義的方法,它從具體的同事對(duì)象接收消息剃浇,向具體同事對(duì)象發(fā)出命令
Colleague:抽象同事類角色巾兆,定義了中介者對(duì)象的接口,它只知道中介者而不知道其他的同事對(duì)象
ConcreteColleagueA/B:具體同事類角色虎囚,繼承于抽象同事類角塑,每個(gè)具體同事類都知道本身在小范圍內(nèi)的TF喲里,而不知道它在大范圍內(nèi)的目的

簡(jiǎn)單實(shí)現(xiàn):計(jì)算機(jī)的組成

在Android源碼中: Keyguard鎖屏

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):如果類間的依賴關(guān)系如網(wǎng)關(guān)般復(fù)雜淘讥,對(duì)依賴關(guān)系進(jìn)行解耦使邏輯結(jié)構(gòu)清晰
缺點(diǎn):如果依賴關(guān)系不復(fù)雜圃伶,使用中介者模式反而使得原本不復(fù)雜的邏輯結(jié)構(gòu)變得復(fù)雜

十八、編程好幫手——代理模式
定義:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問

使用場(chǎng)景:當(dāng)無法或不想直接訪問某個(gè)對(duì)象或訪問某個(gè)對(duì)象存在困難時(shí)可以通過一個(gè)代理對(duì)象來間接訪問蒲列,為了保證客戶端使用的透明性窒朋,委托對(duì)象與代理對(duì)象需要實(shí)現(xiàn)相同的接口

UML類圖
Subject:抽象主題類
RealSubject:真實(shí)主題類
ProxySubject:代理類
Client:客戶類

簡(jiǎn)單實(shí)現(xiàn):代理律師

在Android源碼中:ActivityManagerProxy代理類

Android中的Binder跨進(jìn)程通信機(jī)制與AIDL

實(shí)戰(zhàn) :對(duì)于不同布局通知選擇

小結(jié)
缺點(diǎn):類的增加

十九、物以類聚——組合模式
介紹:Composite Pattern也稱為部分整體模式(Part-Whole Pattern)蝗岖,結(jié)構(gòu)型設(shè)計(jì)模式侥猩,它將一組相似的對(duì)象看作一個(gè)對(duì)象處理,并根據(jù)一個(gè)樹狀結(jié)構(gòu)來組合對(duì)象抵赢,然后提供一個(gè)統(tǒng)一的方法去訪問相應(yīng)的對(duì)象欺劳,以此忽略掉對(duì)象與對(duì)象集合之間的差別。

定義:將對(duì)象組合成樹形結(jié)構(gòu)以表示“部分——整體”的層次結(jié)構(gòu)铅鲤,使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性划提。

使用場(chǎng)景
表示對(duì)象的部分——整體層次結(jié)構(gòu)時(shí)。
從一個(gè)整體中能夠獨(dú)立出部分模塊或功能的場(chǎng)景彩匕。

UML類圖
Component:抽象根節(jié)點(diǎn)腔剂,為組合中的對(duì)象聲明接口
Composite:定義有子節(jié)點(diǎn)的那些枝干節(jié)點(diǎn)的行為,存儲(chǔ)子節(jié)點(diǎn)驼仪,在Component接口中實(shí)現(xiàn)與子節(jié)點(diǎn)有關(guān)的操作
Leaf:在組合中表示葉子節(jié)點(diǎn)對(duì)象掸犬,葉子節(jié)點(diǎn)沒有子節(jié)點(diǎn)袜漩,在組合中定義節(jié)點(diǎn)對(duì)象的行為
Client:通過Component接口操縱組合節(jié)點(diǎn)的對(duì)象

簡(jiǎn)單實(shí)現(xiàn):文件和文件夾

在Android源碼中:View與ViewGroup的嵌套組合

為什么ViewGroup有容器的功能

小結(jié)
優(yōu)點(diǎn):可以清楚地定義分層次的復(fù)雜對(duì)象肢簿,表示對(duì)象的全部或部分層次冤灾,它讓高層模塊忽略了層次的差異,方便對(duì)整個(gè)層次結(jié)構(gòu)進(jìn)行控制堕担;高層模塊可以一致地使用一個(gè)組合結(jié)構(gòu)或其中單個(gè)對(duì)象介褥,不必關(guān)心處理的是單個(gè)對(duì)象還是整個(gè)組合結(jié)構(gòu)座掘,簡(jiǎn)化了高層模塊的代碼;增加新的枝干構(gòu)件和葉子構(gòu)件都很方便柔滔,無須對(duì)現(xiàn)有類庫進(jìn)行任何修改溢陪,符合“開閉原則”;為樹形結(jié)構(gòu)的面向?qū)ο髮?shí)現(xiàn)提供了一種靈活的解決方案睛廊,通過路子對(duì)象和枝干對(duì)象的遞歸組合形真,可以形成復(fù)雜的樹形結(jié)構(gòu),但對(duì)樹形結(jié)構(gòu)的控制卻非常簡(jiǎn)單超全。
缺點(diǎn):在新增構(gòu)件時(shí)不好對(duì)枝干中的構(gòu)件類型進(jìn)行限制咆霜,不能依賴類型系統(tǒng)來施加這些約束,因?yàn)樵诖蠖鄶?shù)情況下嘶朱,它們都來自于相同的抽象層蛾坯,此時(shí),必須進(jìn)行類型檢查來實(shí)現(xiàn)疏遏,這個(gè)實(shí)現(xiàn)過程較為復(fù)雜脉课。

二十、得心應(yīng)手的“粘合劑”——適配器模式
定義:適配器模式把一個(gè)類的接口變換成客戶端所期待的另一種接口财异,從而使原本因接口不匹配而無法在一起工作的兩個(gè)類能夠在一起工作下翎。

使用場(chǎng)景
系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要宝当,即接口不兼容
想要建立一個(gè)可以重復(fù)使用的類视事,用于一些彼此之間沒有太大關(guān)聯(lián)的一些類,包括一些可能在將來引進(jìn)的類一起工作
需要一個(gè)統(tǒng)一的輸出接口庆揩,而輸入端的類型不可預(yù)知

UML類圖
Target:目標(biāo)角色
Adaptee:現(xiàn)在需要適配的接口
Adapter:適配器角色俐东,

簡(jiǎn)單示例:220V電壓轉(zhuǎn)換為5V

在Android源碼中: ListView的Adapter

嘗試拓展

實(shí)戰(zhàn)演示

小結(jié)
優(yōu)點(diǎn):更好的復(fù)用性、更好的擴(kuò)展性
缺點(diǎn):過多使用適配器订晌,會(huì)讓系統(tǒng)非常零亂虏辫,不易整體把握

二十一、裝飾模式
介紹:其使用一種對(duì)客戶端透明的方式來動(dòng)態(tài)地?cái)U(kuò)展對(duì)象的功能锈拨,同時(shí)它也是繼承關(guān)系的一種替代方案之一砌庄。

定義:動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說,裝飾模式生成子類更為靈活娄昆。

使用場(chǎng)景:需要透明且動(dòng)態(tài)地?cái)U(kuò)展類的功能時(shí)

UML類圖
Component:抽象組件
ConcreteComponent:組件具體實(shí)現(xiàn)類
Decorator:抽象裝飾者
ConcreteDecoratorA:裝飾者具體實(shí)現(xiàn)類

簡(jiǎn)單實(shí)現(xiàn):穿衣服

在Android源碼中:Context類

Context與ContextImpl

模式實(shí)戰(zhàn)

小結(jié)

二十二佩微、對(duì)象共享,避免創(chuàng)建多對(duì)象——享元模式
定義: 使用共享對(duì)象可有效地支持大師的細(xì)粒度的對(duì)象

使用場(chǎng)景
系統(tǒng)中存在大量的相似對(duì)象
細(xì)粒度的對(duì)象都具備較接近的外部狀態(tài)萌焰,而且內(nèi)部狀態(tài)與環(huán)境無關(guān)哺眯,也就是說對(duì)象沒有特定身份
需要緩沖池的場(chǎng)景

UML類圖
Flyweight:享元對(duì)象抽象基類或者接口
ConcreateFlyweight:具體的享元對(duì)象
FlyweightFactory:享元工廠

簡(jiǎn)單示例:買票軟件

在Android源碼中:Handler、Looper

深度拓展

小結(jié)
優(yōu)點(diǎn):大幅度地降低內(nèi)存中對(duì)象的數(shù)量
缺點(diǎn):使得系統(tǒng)更加復(fù)雜扒俯;將享元對(duì)象的狀態(tài)外部化奶卓,而讀取外部狀態(tài)使得運(yùn)行時(shí)間稍微變長

二十三、統(tǒng)一編程接口——外觀模式
介紹:Facade在第三方SDK中應(yīng)用廣泛撼玄,通過一個(gè)外觀類使得整個(gè)系統(tǒng)的接口只有一個(gè)統(tǒng)一的高層接口夺姑。

定義:要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對(duì)象進(jìn)行。Facade模式提供一個(gè)高層次的接口掌猛,使得子系統(tǒng)更易于使用

使用場(chǎng)景
為一個(gè)復(fù)雜子系統(tǒng)提供一個(gè)簡(jiǎn)單接口
當(dāng)你需要構(gòu)建一個(gè)層次結(jié)構(gòu)的子系統(tǒng)時(shí)瑟幕,使用Facade模式定義子系統(tǒng)中每層的入口點(diǎn)。如果子系統(tǒng)之間是相互依賴的留潦,你可以讓它們僅通過Facade接口進(jìn)行通信,從而簡(jiǎn)化了它們之間的依賴關(guān)系

UML類圖
Facade:系統(tǒng)對(duì)外的統(tǒng)一接口辣往,系統(tǒng)內(nèi)部系統(tǒng)地工作
SystemA兔院、SystemB、SystemC:子系統(tǒng)接口

簡(jiǎn)單示例:手機(jī)

在Android源碼中:ContextImpl

深度拓展

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):對(duì)客戶程序隱藏子系統(tǒng)細(xì)節(jié)站削,因而減少了客戶對(duì)于子系統(tǒng)的耦合坊萝,能夠擁抱變化;外觀類對(duì)子系統(tǒng)的接口封裝许起,使得系統(tǒng)更易于使用
缺點(diǎn):外觀類接口膨脹十偶;外觀類沒有遵循開閉原則,當(dāng)業(yè)務(wù)出現(xiàn)變更時(shí)园细,可能需要直接修改外觀類

二十四惦积、連接兩地的交通樞紐——橋接模式
定義:將抽象部分與實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地進(jìn)行變化

使用場(chǎng)景
任何多維度變化類或者說多個(gè)樹狀類之間的耦合都可以使用橋接模式來實(shí)現(xiàn)解耦
如果一個(gè)系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性猛频,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系狮崩,可能通過橋接模式使它們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系
對(duì)于那些不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加的系統(tǒng),也可以考慮使用橋接模式
一個(gè)類存在兩個(gè)獨(dú)立變化的維度鹿寻,且這兩個(gè)維度都需要進(jìn)行擴(kuò)展

UML類圖
Abstraction:抽象部分
RefinedAbstraction:優(yōu)化的抽象部分
Implementor:實(shí)現(xiàn)部分
ConcreteImplementorA/ConcreteImplementorB:實(shí)現(xiàn)部分的具體實(shí)現(xiàn)
Client:客戶類

簡(jiǎn)單實(shí)現(xiàn):咖啡大小杯是否加糖

在Android源碼中:Window與WindowManager

關(guān)于WindowManagerService

實(shí)戰(zhàn)

小結(jié)
優(yōu)點(diǎn):分離抽象與實(shí)現(xiàn)睦柴、靈活的擴(kuò)展、對(duì)客戶來說透明的實(shí)現(xiàn)
缺點(diǎn):不容易設(shè)計(jì)

二十五毡熏、MVC的介紹與實(shí)戰(zhàn)
MVC在Android中的實(shí)現(xiàn)
ListView與Adapter
圖片顯示實(shí)例:

public class Model {
    private final Handler mHandler = new Handler();
 private OnStateChangeListener mListener;
private Bitmap mBitmap;
    private Context mContext;
public interface OnStateChangeListener {
        void onStateChanged(Bitmap image);
    }
public Model(Context context) {
        mContext = context;
        mBitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.ic_launcher);
    }
public void setOnStateChangeListener(OnStateChangeListener listener) {
        mListener = listener;
    }
public void loadImage() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    mBitmap = BitmapFactory.decodeResource(mContext.getResources(),R.mipmap.ic_launcher);
                    if (null != mListener)
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mListener.onStateChanged(mBitmap);
                            }
                        });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }
public void clear() {
        mBitmap = null;
        if (null != mListener)
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mListener.onStateChanged(null);
                }
            });
    }
public Bitmap getBitmap() {
        return mBitmap;
}
}
public class MainActivity extends AppCompatActivity implements Model.OnStateChangeListener{
    private ImageView mIVImage;
    private Model mModel;
@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
mModel = new Model(this);
        mModel.setOnStateChangeListener(this);
mIVImage = (ImageView) findViewById(R.id.main_image_iv);
        mIVImage.setImageBitmap(mModel.getBitmap());
    }
public void onClick(View view) {
        switch (view.getId()) {
            case R.id.main_load_btn:
                mModel.loadImage();
                break;
            case R.id.main_clear_btn:
                mModel.clear();
                break;
        }
    }
@Override
    public void onStateChanged(Bitmap image) {
        mIVImage.setImageBitmap(image);
    }
}

二十六坦敌、MVP應(yīng)用架構(gòu)模式
MVP模式的三個(gè)角色
Presenter——交互中間人:主要作為溝通View和Model的橋梁,它從Model層檢索數(shù)據(jù)后,返回給View層狱窘,使得View和Model之間沒有耦合杜顺,也將業(yè)務(wù)邏輯從View角色上抽離出來。
View——用戶界面:通常指Activity训柴、Fragment或者某個(gè)View控件哑舒,它含有一個(gè)Presenter成員變量。通常View需要實(shí)現(xiàn)一個(gè)邏輯接口幻馁,將View上的操作通過會(huì)轉(zhuǎn)交給Presenter進(jìn)行實(shí)現(xiàn)洗鸵,最后,Presenter調(diào)用View邏輯接口將結(jié)果返回給View元素仗嗦。
Model——數(shù)據(jù)的存缺毂酢:對(duì)于一個(gè)結(jié)構(gòu)化的App來說,Model角色主要是提供數(shù)據(jù)的存取功能稀拐。Presenter需要通過Model層存儲(chǔ)火邓、獲取數(shù)據(jù),Model就像一個(gè)數(shù)據(jù)倉庫德撬。更直白地說铲咨,Model是封裝了數(shù)據(jù)庫DAO或者網(wǎng)絡(luò)獲取數(shù)據(jù)的角色,或者兩種數(shù)據(jù)獲取方式的集合蜓洪。

NavigationView中的MVP模式:NavigationView實(shí)際上是一個(gè)FrameLayout纤勒,在這個(gè)FrameLayout中又包含了一個(gè)RecyclerView。如果用戶設(shè)置了Header布局隆檀,那么NavigationView就把這個(gè)Header作為RecyclerView的第一個(gè)Item View摇天,在Header的下面就是菜單列表。

MVP的實(shí)現(xiàn):開發(fā)技術(shù)前線APP

MVP與Activity恐仑、Fragment的生命周期:
由于Presenter持有了MainActivity的強(qiáng)引用泉坐,如果在請(qǐng)求結(jié)束之前Activity被銷毀,那么由于網(wǎng)絡(luò)請(qǐng)求還沒有返回裳仆,會(huì)導(dǎo)致內(nèi)存泄露腕让。可以通過弱引用和Activity歧斟、Fragment的生命周期來解決這個(gè)問題记某。首先建立一個(gè)Presenter抽象類,View類型通過這個(gè)抽象類的泛型傳遞進(jìn)來构捡,Presenter對(duì)這個(gè)View持有弱引用液南。然后創(chuàng)建一個(gè)MVPBaseAcitivity基類,通過這個(gè)基類的生命周期函數(shù)來控制它與Presenter的關(guān)系勾徽。

public abstract class BasePresenter<T> {
  protected Reference<T> mViewRef;
  public void aatchView(T view) {
    mViewRef = new WeakReference<T>(view);
  }
  protected T getView() {
    return mViewRef.get();
  }
  public boolean isViewAttached() {
    return mViewRef != null && mviewRef.get != null;
  }
  public void detachView() {
    if(mViewRef != null) {
      mViewRef.clear();
      mViewRef = null;
    }
  }
}

public abstract class MVPBaseActivity<V,Textends BasePresenter<V>extends Activity {
  protected T mPresenter;
  @SuppressWarnings("unchecked")
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mPresenter = createPresenter();
    mPresenter.accachView((V) this);
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    mPresenter.detachView();
  }
  protected abstract T cratePresenter();
}

二十七滑凉、MVVM應(yīng)用淺析
介紹:MVVC與MVC、MVP的本質(zhì)是一樣的,都是將邏輯分層解耦的產(chǎn)物畅姊,與MVP不同的是咒钟,在ViewModel中有一個(gè)叫做Binder或DataBinding Engine的東西,之間在MVP中由Presenter負(fù)責(zé)的View和Model之間的數(shù)據(jù)邏輯操作就交給這個(gè)Binder去處理若未,而在View中我們只需要聲明View上顯示的內(nèi)容是Model的哪一塊數(shù)據(jù)朱嘴,將其與之綁定在一起即可,最后當(dāng)ViewModel對(duì)Model層的相關(guān)數(shù)據(jù)進(jìn)行更新的時(shí)候粗合,Binder會(huì)將更新后的數(shù)據(jù)傳遞給View萍嬉,View則根據(jù)新的數(shù)據(jù)刷新自己,同樣地隙疚,當(dāng)用戶對(duì)View層操作的時(shí)候壤追,如果涉及對(duì)數(shù)據(jù)的更新,Binder同樣也會(huì)把數(shù)據(jù)更新到Model層供屉。

MVVM的基本結(jié)構(gòu)
Model:MVVM的Model層與MVC行冰、MVP沒太大區(qū)別,也主要是封裝數(shù)據(jù)存儲(chǔ)或操作的一些邏輯伶丐,與兩者不同的是Model會(huì)提供一系列的實(shí)體類用作與UI進(jìn)行綁定悼做,ViewModel則會(huì)在修改這些數(shù)據(jù)后將數(shù)據(jù)變化告訴View層并使UI刷新
View:View層與MVC、MVP一樣哗魂,都是用于處理界面的邏輯且不參與業(yè)務(wù)邏輯相關(guān)的操作肛走,只負(fù)責(zé)顯示由ViewModel提供的數(shù)據(jù)
ViewModel:本質(zhì)是視圖模型與視圖狀態(tài)的全稱,其主要職責(zé)就是為View層提供一個(gè)可供其顯示的數(shù)據(jù)模型并且同時(shí)搜集啡彬、處理這些數(shù)據(jù)

View與ViewModel之間的交互:Binder的實(shí)現(xiàn)除第三方框架外,還有Command命令模式故硅,View和ViewModel分別可以看作是:Invoker和Receiver

MVVM在Android中的應(yīng)用與DataBinding使用淺析:

//集成DataBinding庶灿,在Module的build.gradle文件中添加如下代碼:
dataBinding {
        enabled = true
    }

//修改布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <import type="com.lewanjiang.mvvmtest.User" />
        <variable
            name="user"
            type="com.lewanjiang.mvvmtest.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@(User.fistName)"
            android:textSize="20sp"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@(user.lastName)"
            android:textSize="25sp"/>
    </LinearLayout>
</layout>

//定義實(shí)體類
public class User {
    private String firstName;
    private String lastName;

    public User(String firstName,String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

//修改MainActivity
public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding mActivityMainBinding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mActivityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main);
        User user = new User("bob","Jiang");
        mActivityMainBinding.setUser(user);
    }
}

MVVM的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):相對(duì)于MVP而言,不需要手動(dòng)去處理大師的View和Model相關(guān)的操作吃衅,因?yàn)殡p向綁定往踢,只需要保證Model正確,那么View就一定是正確的徘层,讓測(cè)試變得簡(jiǎn)單

MVC峻呕、MVP與MVVM的異同

二十八、易混淆的設(shè)計(jì)模式
簡(jiǎn)單工廠趣效、工廠方法瘦癌、抽象工廠、Builder模式的區(qū)別
簡(jiǎn)單工廠:一個(gè)工廠方法創(chuàng)建不同類型的對(duì)象
工廠方法:一個(gè)具體的工廠類負(fù)責(zé)創(chuàng)建一個(gè)具體對(duì)象類型
抽象工廠跷敬、一個(gè)具體的工廠類負(fù)責(zé)創(chuàng)建一系列相關(guān)的對(duì)象
Builder:對(duì)象的構(gòu)建與表示分享讯私,它更注重對(duì)象的創(chuàng)建過程

代理與裝飾模式、橋接模式
代理模式:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問
裝飾模式:動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來說斤寇,裝飾模式相比生成子類更為靈活
橋接模式:將抽象和實(shí)現(xiàn)解耦桶癣,使得兩者可以獨(dú)立地變化

外觀模式與中介模式
外觀模式:要求一個(gè)子系統(tǒng)的外部與其內(nèi)部的通信必須通過一個(gè)統(tǒng)一的對(duì)象進(jìn)行。外觀模式提供一個(gè)高層次的接口娘锁,使得子系統(tǒng)更易于使用牙寞。
中介模式:用一個(gè)中介對(duì)象封裝一系列的對(duì)象交互,中介者使各對(duì)象不需要顯示地相互作用莫秆,從而使其耦合松散间雀,而且可以獨(dú)立地改變它們之間的交互。

策略與狀態(tài)模式馏锡、命令模式
策略模式:定義一組算法雷蹂,將每個(gè)算法都封裝進(jìn)來,并且使它們之間可以互換
狀態(tài)模式:當(dāng)一個(gè)對(duì)象內(nèi)在狀態(tài)改變時(shí)允許其改變行為杯道,這個(gè)對(duì)象看起來介改變了其類匪煌。
命令模式:將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓你使用不同的請(qǐng)求把客戶端參數(shù)化党巾,對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志萎庭,可以提供命令的撤銷和恢復(fù)功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末齿拂,一起剝皮案震驚了整個(gè)濱河市驳规,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌署海,老刑警劉巖吗购,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異砸狞,居然都是意外死亡捻勉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門刀森,熙熙樓的掌柜王于貴愁眉苦臉地迎上來踱启,“玉大人,你說我怎么就攤上這事研底〔撼ィ” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵榜晦,是天一觀的道長冠蒋。 經(jīng)常有香客問我,道長乾胶,這世上最難降的妖魔是什么浊服? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任统屈,我火速辦了婚禮,結(jié)果婚禮上牙躺,老公的妹妹穿的比我還像新娘愁憔。我一直安慰自己,他們只是感情好孽拷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布吨掌。 她就那樣靜靜地躺著,像睡著了一般脓恕。 火紅的嫁衣襯著肌膚如雪膜宋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天炼幔,我揣著相機(jī)與錄音秋茫,去河邊找鬼。 笑死乃秀,一個(gè)胖子當(dāng)著我的面吹牛肛著,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跺讯,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼枢贿,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了刀脏?” 一聲冷哼從身側(cè)響起局荚,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎愈污,沒想到半個(gè)月后耀态,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡暂雹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年首装,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擎析。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簿盅,死狀恐怖挥下,靈堂內(nèi)的尸體忽然破棺而出揍魂,到底是詐尸還是另有隱情,我是刑警寧澤棚瘟,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布现斋,位于F島的核電站,受9級(jí)特大地震影響偎蘸,放射性物質(zhì)發(fā)生泄漏庄蹋。R本人自食惡果不足惜瞬内,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望限书。 院中可真熱鬧虫蝶,春花似錦、人聲如沸倦西。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扰柠。三九已至粉铐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間卤档,已是汗流浹背蝙泼。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劝枣,地道東北人汤踏。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像哨免,于是被迫代替她去往敵國和親茎活。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

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