轉(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é)原則
- 開放封閉原則
- 里氏替換原則
- 依賴倒置
- 迪米特原則
- 接口隔離原則
單一職責(zé)原則
一個(gè)類應(yīng)該僅有一個(gè)引起它變化的原因,即不要讓一個(gè)類承擔(dān)過多的職責(zé),以此降低耦合性。
開放封閉原則
類、函數(shù)、模塊應(yīng)該是可以擴(kuò)展的,但是不可以修改,即對擴(kuò)展開放,修改封閉。
里氏替換原則
所有引用基類的地方都能透明地替換為子類對象,即可以在定義時(shí)盡量使用基類對象,等到運(yùn)行時(shí)再確定其子類類型,用子類對象來替換父類對象。
依賴倒置原則
高層、底層模塊、模塊間和細(xì)節(jié)都應(yīng)該依賴于抽象,即通過接口或抽象類產(chǎn)生依賴關(guān)系。
迪米特原則
一個(gè)軟件實(shí)體應(yīng)該盡可能少地與其它實(shí)體發(fā)生相互作用,即最少知識原則。
如果一個(gè)對象需要調(diào)用其它對象的某個(gè)方法,可以通過第三者來調(diào)用,這個(gè)第三者的作用就如Android中的事件總線EventBus一樣。
接口隔離原則
一個(gè)類對另一個(gè)類的依賴應(yīng)該建立在最小的接口上。
二、設(shè)計(jì)模式分類
GoF提出的設(shè)計(jì)模式有23種,按照目的準(zhǔn)則分類,有三大類:
- 創(chuàng)建性設(shè)計(jì)模式5種:單例、工廠方法、抽象工廠、建造者、原型。
- 結(jié)構(gòu)型設(shè)計(jì)模式7種:適配器、裝飾、代理、外觀、橋接、組合、享元。
- 行為型設(shè)計(jì)模式11種:策略、模板方法、觀察者、迭代器、責(zé)任鏈、命令、備忘錄、狀態(tài)、訪問者、中介者、解釋器。
三、Android開發(fā)常用設(shè)計(jì)模式
1、創(chuàng)建型設(shè)計(jì)模式
單例模式
保證一個(gè)類僅有一個(gè)實(shí)例,提供一個(gè)訪問它的全局訪問點(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í)例,則會造成內(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)行同步,會有不必要的同步開銷。
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í)例的可見性。
- DCL在一定程度上解決了資源的消耗和多余的同步、線程安全等問題,但是在某些情況下會失效。
假設(shè)線程A執(zhí)行到instance = new Singleton()語句,看起來只有一行代碼,但實(shí)際上它并不是原子操作,這句代碼最終會被編譯成多條匯編指令,它大致做了3件事:
1)給instance的實(shí)例分配內(nèi)存。
2)調(diào)用Singleton()構(gòu)造函數(shù),初始化成員字段。
3)將instance對象指向分配的內(nèi)存空間(此時(shí)instance就不是null了)。
但是,由于Java編譯器允許處理器亂序執(zhí)行,以及JDK1.5之前JMM中的Cache、寄存器到主內(nèi)存回寫順序的規(guī)定,上面的2和3的順序是無法保證的,也就是說,執(zhí)行順序可能是1-2-3也可能是1-3-2。如果是后者,并且在3執(zhí)行完畢、2未執(zhí)行之前,被切換到線程B上,這時(shí)候instance因?yàn)橐呀?jīng)在線程A內(nèi)執(zhí)行過了3,instance已經(jīng)是非空了,所以,線程B直接取走instance,再使用時(shí)就會出錯(cuò),這就是DCL失效問題,而且這種難以跟蹤難以重現(xiàn)的錯(cuò)誤可能會隱藏很久。
在JDK1.5之后,SUN官方已經(jīng)注意到這種問題,調(diào)整了JVM,具體化了volatile關(guān)鍵字,因此,如果JDK1.5或之后的版本,只需要將instance的定義改成private volatile static Singleton instance = null就可以保證instance對象每次都是從主內(nèi)存中讀取,就可以使用DCL的寫法來完成單例模式。當(dāng)然,volatile或多或少也會影響到性能,但考慮到程序的正確性,這點(diǎn)犧牲也是值得的。
DCL優(yōu)點(diǎn):資源利用率高,第一次執(zhí)行g(shù)etInstance時(shí)單例對象才會被實(shí)例化,效率高。
缺點(diǎn):第一次加載稍慢,也由于JMM的原因?qū)е屡紶枙?。在高并發(fā)環(huán)境下也有一定的缺陷,雖然發(fā)生概率很小。DCL模式是使用最多的單例實(shí)現(xiàn)方式,它能夠在需要時(shí)才實(shí)例化對象,并且能在絕大多數(shù)場景下保證對象的唯一性,除非你的代碼在并發(fā)場景比較復(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)建是線程安全的,并且在任何情況下都是單例。
- 簡單、可讀性不高。
注意:上面的幾種單例模式創(chuàng)建的單例對象被反序列化時(shí)會重新創(chuàng)建實(shí)例,可以重寫readReslove方法返回當(dāng)前的單例對象。
簡單工廠模式(補(bǔ)充)
也稱為靜態(tài)工廠方法模式,由一個(gè)工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例。
簡單工廠模式中有如下角色:
- 工廠類:核心,負(fù)責(zé)創(chuàng)建所有實(shí)例的內(nèi)部邏輯,由外界直接調(diào)用。
- 抽象產(chǎn)品類:要?jiǎng)?chuàng)建所有對象的抽象父類,負(fù)責(zé)描述所有實(shí)例所共有的公共接口。
- 具體產(chǎn)品類:要?jiǎng)?chuàng)建的產(chǎ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)建的對象比較少的情況。
- 避免直接實(shí)例化類,降低耦合性。
- 增加新產(chǎn)品需要修改工廠,違背開放封閉原則。
工廠方法模式
定義一個(gè)用于創(chuàng)建對象的接口,使類的實(shí)例化延遲到子類。
工廠方法有以下角色:
- 抽象產(chǎn)品類。
- 具體產(chǎn)品類。
- 抽象工廠類:返回一個(gè)泛型的產(chǎn)品對象。
- 具體工廠類:返回具體的產(chǎn)品對象。
簡單示例
抽象產(chǎn)品類和具體產(chǎ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;
}
}
- 相比簡單工廠,如果我們需要新增產(chǎn)品類,無需修改工廠類,直接創(chuàng)建產(chǎn)品即可。
建造者模式
將一個(gè)復(fù)雜對象的構(gòu)建和它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
建造者有以下角色:
- 導(dǎo)演類:負(fù)責(zé)安排已有模塊的安裝順序,最后通知建造者開始建造。
- 建造者:抽象Builder類,用于規(guī)范產(chǎn)品的組建。
- 具體建造者:實(shí)現(xiàn)抽象Builder類的所有方法,并返回建造好的對象。
- 產(chǎ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ò)展。
- 會產(chǎn)生多余的建造者對象和導(dǎo)演類。
2、結(jié)構(gòu)型設(shè)計(jì)模式
1、代理模式
為其它對象提供一種代理以控制這個(gè)對象的訪問。
代理模式中有以下角色:
- 抽象主題類:聲明真實(shí)主題和代理的共同接口方法。
- 真實(shí)主題類。
- 代理類:持有對真實(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í)通過反射來動(dòng)態(tài)地生成代理類的對象,并確定到底來代理誰。
動(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è)對象添加一些額外的職責(zé)。
裝飾模式有以下角色:
- 抽象組件:接口/抽象類,被裝飾的最原始的對象。
- 具體組件:被裝飾的具體對象。
- 抽象裝飾者:擴(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ò)展對象的功能,在運(yùn)行時(shí)能夠使用不同的裝飾器實(shí)現(xiàn)不同的行為。
- 比繼承更易出錯(cuò),旨在必要時(shí)使用。
外觀模式(門面模式)
一個(gè)子系統(tǒng)的內(nèi)部和外部通信必須通過一個(gè)統(tǒng)一的對象進(jìn)行。即提供一個(gè)高層的接口,方便子系統(tǒng)更易于使用。
外觀模式有以下角色:
- 外觀類:將客戶端的請求代理給適當(dāng)?shù)淖酉到y(tǒng)對象。
- 子系統(tǒng)類:可以有一個(gè)或多個(gè)子系統(tǒng),用于處理外觀類指派的任務(wù)。注意子系統(tǒng)不含外觀類的引用。
簡單示例
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();
- 將對子系統(tǒng)的依賴轉(zhuǎn)換為對外觀類的依賴。
- 對外部隱藏子系統(tǒng)的具體實(shí)現(xiàn)。
- 這種外觀特性增強(qiáng)了安全性。
享元模式
使用共享對象有效支持大量細(xì)粒度(性質(zhì)相似)的對象。
額外的兩個(gè)概念:
- 1、內(nèi)部狀態(tài):共享信息,不可改變。
- 2、外部狀態(tài):依賴標(biāo)記,可以改變。
享元模式有以下角色:
- 抽象享元角色:定義對象內(nèi)部和外部狀態(tài)的接口。
- 具體享元角色:實(shí)現(xiàn)抽象享元角色的任務(wù)。
- 享元工廠:管理對象池及創(chuàng)建享元對象。
簡單示例
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)建的對象,后面的都是從對象池中取出的緩存對象。
適配器模式
將一個(gè)接口轉(zhuǎn)換為另一個(gè)需要的接口。
適配器有以下角色:
- 要轉(zhuǎn)換的接口。
- 要轉(zhuǎn)換的接口的實(shí)現(xiàn)類。
- 轉(zhuǎn)換后的接口。
- 轉(zhuǎn)換后的接口的實(shí)現(xià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() {
// 火雞沒有鴨子飛的遠(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è)算法都封裝起來,并且可相互替換。這使得算法可以獨(dú)立于調(diào)用者而單獨(dú)變化。
策略模式有以下角色:
- 上下文角色:用來操作策略使用的上下文環(huá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é)。
- 避免使用多重條件語句。
- 易于擴(kuò)展
- 每一個(gè)策略都是一個(gè)類,復(fù)用性小。
- 上層模塊必須知道有哪些策略類,與迪米特原則相違背。
2、模板方法模式
定義了一套算法框架,將某些步驟交給子類去實(shí)現(xiàn)。使得子類不需改變框架結(jié)構(gòu)即可重寫算法中的某些步驟。
模板方法模式有以下角色:
- 抽象類:定義了一套算法框架。
- 具體實(shí)現(xià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() {
// 沒有武器,不做處理
}
@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)子類對父類的反向控制。
- 可以把核心或固定的邏輯搬移到基類,其它細(xì)節(jié)交給子類實(shí)現(xiàn)。
- 每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類,復(fù)用性小。
3、觀察者模式(發(fā)布 - 訂閱模式)
定義對象間的一種1對多的依賴關(guān)系,每當(dāng)這個(gè)對象的狀態(tài)改變時(shí),其它的對象都會接收到通知并被自動(dòng)更新。
觀察者模式有以下角色:
- 抽象被觀察者:將所有已注冊的觀察者對象保存在一個(gè)集合中。
- 具體被觀察者:當(dāng)內(nèi)部狀態(tài)發(fā)生變化時(shí),將會通知所有已注冊的觀察者。
- 抽象觀察者:定義了一個(gè)更新接口,當(dāng)被觀察者狀態(tài)改變時(shí)更新自己。
- 具體被觀察者:實(shí)現(xià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è)被觀察者卡頓,會影響整體的執(zhí)行效率。采用異步機(jī)制可解決此類問題。