轉(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é)原則
- 開(kāi)放封閉原則
- 里氏替換原則
- 依賴倒置
- 迪米特原則
- 接口隔離原則
單一職責(zé)原則
一個(gè)類應(yīng)該僅有一個(gè)引起它變化的原因惕它,即不要讓一個(gè)類承擔(dān)過(guò)多的職責(zé),以此降低耦合性因块。
開(kāi)放封閉原則
類、函數(shù)籍铁、模塊應(yīng)該是可以擴(kuò)展的涡上,但是不可以修改,即對(duì)擴(kuò)展開(kāi)放寨辩,修改封閉吓懈。
里氏替換原則
所有引用基類的地方都能透明地替換為子類對(duì)象,即可以在定義時(shí)盡量使用基類對(duì)象靡狞,等到運(yùn)行時(shí)再確定其子類類型耻警,用子類對(duì)象來(lái)替換父類對(duì)象。
依賴倒置原則
高層甸怕、底層模塊甘穿、模塊間和細(xì)節(jié)都應(yīng)該依賴于抽象,即通過(guò)接口或抽象類產(chǎn)生依賴關(guān)系梢杭。
迪米特原則
一個(gè)軟件實(shí)體應(yīng)該盡可能少地與其它實(shí)體發(fā)生相互作用温兼,即最少知識(shí)原則。
如果一個(gè)對(duì)象需要調(diào)用其它對(duì)象的某個(gè)方法武契,可以通過(guò)第三者來(lái)調(diào)用募判,這個(gè)第三者的作用就如Android中的事件總線EventBus一樣荡含。
接口隔離原則
一個(gè)類對(duì)另一個(gè)類的依賴應(yīng)該建立在最小的接口上。
二届垫、設(shè)計(jì)模式分類
GoF提出的設(shè)計(jì)模式有23種释液,按照目的準(zhǔn)則分類,有三大類:
- 創(chuàng)建性設(shè)計(jì)模式5種:?jiǎn)卫按Α⒐S方法误债、抽象工廠、建造者妄迁、原型寝蹈。
- 結(jié)構(gòu)型設(shè)計(jì)模式7種:適配器、裝飾登淘、代理箫老、外觀、橋接黔州、組合槽惫、享元。
- 行為型設(shè)計(jì)模式11種:策略辩撑、模板方法、觀察者仿耽、迭代器合冀、責(zé)任鏈、命令项贺、備忘錄君躺、狀態(tài)、訪問(wèn)者开缎、中介者棕叫、解釋器。
三奕删、Android開(kāi)發(fā)常用設(shè)計(jì)模式
1俺泣、創(chuàng)建型設(shè)計(jì)模式
單例模式
保證一個(gè)類僅有一個(gè)實(shí)例,提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(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í)例谨设,則會(huì)造成內(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)行同步赴肚,會(huì)有不必要的同步開(kāi)銷素跺。
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í)例的可見(jiàn)性横朋。
- DCL在一定程度上解決了資源的消耗和多余的同步仑乌、線程安全等問(wèn)題,但是在某些情況下會(huì)失效琴锭。
假設(shè)線程A執(zhí)行到instance = new Singleton()語(yǔ)句晰甚,看起來(lái)只有一行代碼,但實(shí)際上它并不是原子操作决帖,這句代碼最終會(huì)被編譯成多條匯編指令厕九,它大致做了3件事:
1)給instance的實(shí)例分配內(nèi)存。
2)調(diào)用Singleton()構(gòu)造函數(shù)地回,初始化成員字段扁远。
3)將instance對(duì)象指向分配的內(nèi)存空間(此時(shí)instance就不是null了)。
但是刻像,由于Java編譯器允許處理器亂序執(zhí)行畅买,以及JDK1.5之前JMM中的Cache、寄存器到主內(nèi)存回寫順序的規(guī)定细睡,上面的2和3的順序是無(wú)法保證的谷羞,也就是說(shuō),執(zhí)行順序可能是1-2-3也可能是1-3-2溜徙。如果是后者湃缎,并且在3執(zhí)行完畢、2未執(zhí)行之前蠢壹,被切換到線程B上嗓违,這時(shí)候instance因?yàn)橐呀?jīng)在線程A內(nèi)執(zhí)行過(guò)了3,instance已經(jīng)是非空了图贸,所以蹂季,線程B直接取走instance,再使用時(shí)就會(huì)出錯(cuò)求妹,這就是DCL失效問(wèn)題乏盐,而且這種難以跟蹤難以重現(xiàn)的錯(cuò)誤可能會(huì)隱藏很久。
在JDK1.5之后制恍,SUN官方已經(jīng)注意到這種問(wèn)題父能,調(diào)整了JVM,具體化了volatile關(guān)鍵字净神,因此何吝,如果JDK1.5或之后的版本溉委,只需要將instance的定義改成private volatile static Singleton instance = null就可以保證instance對(duì)象每次都是從主內(nèi)存中讀取,就可以使用DCL的寫法來(lái)完成單例模式爱榕。當(dāng)然瓣喊,volatile或多或少也會(huì)影響到性能,但考慮到程序的正確性黔酥,這點(diǎn)犧牲也是值得的藻三。
DCL優(yōu)點(diǎn):資源利用率高,第一次執(zhí)行g(shù)etInstance時(shí)單例對(duì)象才會(huì)被實(shí)例化跪者,效率高棵帽。
缺點(diǎn):第一次加載稍慢,也由于JMM的原因?qū)е屡紶枙?huì)失敗渣玲。在高并發(fā)環(huán)境下也有一定的缺陷逗概,雖然發(fā)生概率很小。DCL模式是使用最多的單例實(shí)現(xiàn)方式忘衍,它能夠在需要時(shí)才實(shí)例化對(duì)象逾苫,并且能在絕大多數(shù)場(chǎng)景下保證對(duì)象的唯一性,除非你的代碼在并發(fā)場(chǎng)景比較復(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)建是線程安全的,并且在任何情況下都是單例便斥。
- 簡(jiǎn)單至壤、可讀性不高。
注意:上面的幾種單例模式創(chuàng)建的單例對(duì)象被反序列化時(shí)會(huì)重新創(chuàng)建實(shí)例枢纠,可以重寫readReslove方法返回當(dāng)前的單例對(duì)象像街。
簡(jiǎn)單工廠模式(補(bǔ)充)
也稱為靜態(tài)工廠方法模式,由一個(gè)工廠對(duì)象決定創(chuàng)建出哪一種產(chǎn)品類的實(shí)例晋渺。
簡(jiǎn)單工廠模式中有如下角色:
- 工廠類:核心镰绎,負(fù)責(zé)創(chuàng)建所有實(shí)例的內(nèi)部邏輯,由外界直接調(diào)用木西。
- 抽象產(chǎn)品類:要?jiǎng)?chuàng)建所有對(duì)象的抽象父類畴栖,負(fù)責(zé)描述所有實(shí)例所共有的公共接口。
- 具體產(chǎn)品類:要?jiǎng)?chuàng)建的產(chǎn)品八千。
簡(jiǎ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)建的對(duì)象比較少的情況重绷。
- 避免直接實(shí)例化類,降低耦合性膜毁。
- 增加新產(chǎn)品需要修改工廠昭卓,違背開(kāi)放封閉原則。
工廠方法模式
定義一個(gè)用于創(chuàng)建對(duì)象的接口瘟滨,使類的實(shí)例化延遲到子類候醒。
工廠方法有以下角色:
- 抽象產(chǎn)品類。
- 具體產(chǎn)品類室奏。
- 抽象工廠類:返回一個(gè)泛型的產(chǎn)品對(duì)象火焰。
- 具體工廠類:返回具體的產(chǎn)品對(duì)象。
簡(jiǎn)單示例
抽象產(chǎn)品類和具體產(chǎn)品類同簡(jiǎ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;
}
}
- 相比簡(jiǎn)單工廠绒怨,如果我們需要新增產(chǎn)品類纯赎,無(wú)需修改工廠類,直接創(chuàng)建產(chǎn)品即可南蹂。
建造者模式
將一個(gè)復(fù)雜對(duì)象的構(gòu)建和它的表示分離犬金,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。
建造者有以下角色:
- 導(dǎo)演類:負(fù)責(zé)安排已有模塊的安裝順序六剥,最后通知建造者開(kāi)始建造晚顷。
- 建造者:抽象Builder類,用于規(guī)范產(chǎn)品的組建疗疟。
- 具體建造者:實(shí)現(xiàn)抽象Builder類的所有方法该默,并返回建造好的對(duì)象。
- 產(chǎn)品類策彤。
簡(jiǎ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ò)展捧弃。
- 會(huì)產(chǎn)生多余的建造者對(duì)象和導(dǎo)演類。
2擦囊、結(jié)構(gòu)型設(shè)計(jì)模式
1塔橡、代理模式
為其它對(duì)象提供一種代理以控制這個(gè)對(duì)象的訪問(wèn)梅割。
代理模式中有以下角色:
- 抽象主題類:聲明真實(shí)主題和代理的共同接口方法。
- 真實(shí)主題類葛家。
- 代理類:持有對(duì)真實(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í)通過(guò)反射來(lái)動(dòng)態(tài)地生成代理類的對(duì)象双仍,并確定到底來(lái)代理誰(shuí)。
動(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è)對(duì)象添加一些額外的職責(zé)瑟俭。
裝飾模式有以下角色:
- 抽象組件:接口/抽象類翎卓,被裝飾的最原始的對(duì)象。
- 具體組件:被裝飾的具體對(duì)象摆寄。
- 抽象裝飾者:擴(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ò)展對(duì)象的功能述暂,在運(yùn)行時(shí)能夠使用不同的裝飾器實(shí)現(xiàn)不同的行為痹升。
- 比繼承更易出錯(cuò),旨在必要時(shí)使用畦韭。
外觀模式(門面模式)
一個(gè)子系統(tǒng)的內(nèi)部和外部通信必須通過(guò)一個(gè)統(tǒng)一的對(duì)象進(jìn)行疼蛾。即提供一個(gè)高層的接口,方便子系統(tǒng)更易于使用艺配。
外觀模式有以下角色:
- 外觀類:將客戶端的請(qǐng)求代理給適當(dāng)?shù)淖酉到y(tǒng)對(duì)象察郁。
- 子系統(tǒng)類:可以有一個(gè)或多個(gè)子系統(tǒng)衍慎,用于處理外觀類指派的任務(wù)。注意子系統(tǒng)不含外觀類的引用皮钠。
簡(jiǎn)單示例
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();
- 將對(duì)子系統(tǒng)的依賴轉(zhuǎn)換為對(duì)外觀類的依賴乔夯。
- 對(duì)外部隱藏子系統(tǒng)的具體實(shí)現(xiàn)。
- 這種外觀特性增強(qiáng)了安全性款侵。
享元模式
使用共享對(duì)象有效支持大量細(xì)粒度(性質(zhì)相似)的對(duì)象末荐。
額外的兩個(gè)概念:
- 1、內(nèi)部狀態(tài):共享信息新锈,不可改變甲脏。
- 2、外部狀態(tài):依賴標(biāo)記妹笆,可以改變块请。
享元模式有以下角色:
- 抽象享元角色:定義對(duì)象內(nèi)部和外部狀態(tài)的接口。
- 具體享元角色:實(shí)現(xiàn)抽象享元角色的任務(wù)晾浴。
- 享元工廠:管理對(duì)象池及創(chuàng)建享元對(duì)象负乡。
簡(jiǎn)單示例
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)建的對(duì)象狸涌,后面的都是從對(duì)象池中取出的緩存對(duì)象切省。
適配器模式
將一個(gè)接口轉(zhuǎn)換為另一個(gè)需要的接口。
適配器有以下角色:
- 要轉(zhuǎn)換的接口帕胆。
- 要轉(zhuǎn)換的接口的實(shí)現(xiàn)類朝捆。
- 轉(zhuǎn)換后的接口。
- 轉(zhuǎn)換后的接口的實(shí)現(xiàn)類懒豹。
- 適配器類芙盘。
簡(jiǎ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() {
// 火雞沒(méi)有鴨子飛的遠(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è)算法都封裝起來(lái),并且可相互替換鞠鲜。這使得算法可以獨(dú)立于調(diào)用者而單獨(dú)變化宁脊。
策略模式有以下角色:
- 上下文角色:用來(lái)操作策略使用的上下文環(huán)境。屏蔽了高層模塊對(duì)策略和算法的直接訪問(wèn)贤姆。
- 抽象策略角色榆苞。
- 具體策略角色。
簡(jiǎ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é)赊琳。
- 避免使用多重條件語(yǔ)句。
- 易于擴(kuò)展
- 每一個(gè)策略都是一個(gè)類砰碴,復(fù)用性小躏筏。
- 上層模塊必須知道有哪些策略類,與迪米特原則相違背呈枉。
2趁尼、模板方法模式
定義了一套算法框架,將某些步驟交給子類去實(shí)現(xiàn)猖辫。使得子類不需改變框架結(jié)構(gòu)即可重寫算法中的某些步驟酥泞。
模板方法模式有以下角色:
- 抽象類:定義了一套算法框架。
- 具體實(shí)現(xiàn)類啃憎。
簡(jiǎ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() {
// 沒(méi)有武器辛萍,不做處理
}
@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)子類對(duì)父類的反向控制。
- 可以把核心或固定的邏輯搬移到基類贩毕,其它細(xì)節(jié)交給子類實(shí)現(xiàn)悯许。
- 每個(gè)不同的實(shí)現(xiàn)都需要定義一個(gè)子類,復(fù)用性小耳幢。
3、觀察者模式(發(fā)布 - 訂閱模式)
定義對(duì)象間的一種1對(duì)多的依賴關(guān)系,每當(dāng)這個(gè)對(duì)象的狀態(tài)改變時(shí)睛藻,其它的對(duì)象都會(huì)接收到通知并被自動(dòng)更新启上。
觀察者模式有以下角色:
- 抽象被觀察者:將所有已注冊(cè)的觀察者對(duì)象保存在一個(gè)集合中。
- 具體被觀察者:當(dāng)內(nèi)部狀態(tài)發(fā)生變化時(shí)店印,將會(huì)通知所有已注冊(cè)的觀察者冈在。
- 抽象觀察者:定義了一個(gè)更新接口,當(dāng)被觀察者狀態(tài)改變時(shí)更新自己按摘。
- 具體被觀察者:實(shí)現(xiàn)抽象觀察者的更新接口包券。
簡(jiǎ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è)被觀察者卡頓亮元,會(huì)影響整體的執(zhí)行效率。采用異步機(jī)制可解決此類問(wèn)題唠摹。