COMMAND 模式
一個(gè)簡單的 command 模式實(shí)現(xiàn)
public interface IReceiver {
public void action();
}
public class ConcreteReceiver implements IReceiver {
public void action() {
System.out.println("ConcreteReceiver 執(zhí)行 action");
}
}
public interface ICommand {
public void execute();
}
public class ConcreteCommand implements ICommand {
private IReceiver receiver;
public ConcreteCommand(IReceiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
public class Invoker {
public ICommand command;
public Invoker(ICommand command) {
this.command = command;
}
public void action() {
command.execute();
}
}
public class Client {
public static void main(String[] args) {
IReceiver receiver = new ConcreteReceiver();
ICommand command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.action();
}
}
代碼解釋
- IReceiver: 一個(gè)
接收者
接口拱礁,action 是一個(gè)抽象的執(zhí)行方法然爆。 - ConcreteReceiver: 一個(gè)具體的接收者實(shí)現(xiàn)類斤吐,實(shí)現(xiàn)了 action 方法搔涝。
- ICommand: 一個(gè)
命令
接口厨喂,execute 是一個(gè)執(zhí)行命令的抽象方法。 - ConcreteCommand:一個(gè)具體的命令實(shí)現(xiàn)類庄呈,關(guān)聯(lián)了一個(gè) IReceiver 對(duì)象蜕煌,execute 方法的具體類容是執(zhí)行 IReceiver 的 action 方法。
- Invoker: 一個(gè)
調(diào)用者
類诬留,關(guān)聯(lián)了一個(gè) ICommand 對(duì)象斜纪,action 方法實(shí)際上執(zhí)行的是 ICommand 的 execute 方法。 - Client: 一個(gè)
客戶端
類文兑。演示了調(diào)用者
傳遞一個(gè)命令對(duì)象
盒刚,命令對(duì)象
調(diào)用接受者對(duì)象
的 action 方法。在這個(gè)過程中绿贞,命令對(duì)象
充當(dāng)了一個(gè)中間人的角色因块,調(diào)用者
和接收者
命令模式的簡要說明
在 Client 中演示了調(diào)用者
傳遞一個(gè)命令對(duì)象
,命令對(duì)象
調(diào)用接受者對(duì)象
的 action 方法籍铁。在這個(gè)過程中涡上,命令對(duì)象
充當(dāng)了一個(gè)中間人的角色歌懒,將接收者
的執(zhí)行方法進(jìn)行了封裝
子眶,調(diào)用者
和接收者
是完全解耦的。
命令模式是對(duì)命令的封裝失晴。命令模式把發(fā)出命令的責(zé)任和執(zhí)行命令的責(zé)任分割開靡狞,委派給不同的對(duì)象耻警。
每一個(gè)命令都是一個(gè)操作:請(qǐng)求的一方發(fā)出請(qǐng)求要求執(zhí)行一個(gè)操作;接收的一方收到請(qǐng)求甸怕,并執(zhí)行操作甘穿。命令模式允許請(qǐng)求的一方和接收的一方獨(dú)立開來,使得請(qǐng)求的一方不必知道接收請(qǐng)求的一方的接口梢杭,更不必知道請(qǐng)求是怎么被接收温兼,以及操作是否被執(zhí)行、何時(shí)被執(zhí)行武契,以及是怎么被執(zhí)行的募判。
優(yōu)點(diǎn)
- 命令模式使新的命令很容易地被加入到系統(tǒng)里。
- 允許接收請(qǐng)求的一方?jīng)Q定是否要否決請(qǐng)求咒唆。
- 能較容易地設(shè)計(jì)一個(gè)命令隊(duì)列届垫。
- 可以容易地實(shí)現(xiàn)對(duì)請(qǐng)求的撤銷和恢復(fù)。
- 在需要的情況下全释,可以較容易地將命令記入日志装处。
應(yīng)用場(chǎng)景
- 數(shù)據(jù)庫事務(wù)控制
- 設(shè)備控制
- 多線程核心
- GUI 的 do/undo 管理
參考
- https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html
- https://www.cnblogs.com/java-my-life/archive/2012/06/01/2526972.html
- http://www.runoob.com/design-pattern/command-pattern.html
- https://blog.csdn.net/hguisu/article/details/7549895
- https://blog.csdn.net/zhengzhb/article/details/7550895
TEMPLATE METHOD 模式和 STRATEGY 模式
在了解 template method 模式和 strategy 模式之前先看這兩個(gè)模式的簡單實(shí)現(xiàn)。
一個(gè) template method 模式的簡單實(shí)現(xiàn)
public abstract class AbstractDaily {
public abstract void eat();
public abstract void sleep();
public abstract void doSomething();
public void myDaily() {
eat();
doSomething();
sleep();
}
}
public class StudentDaily extends AbstractDaily {
public void eat() {
System.out.println("吃點(diǎn)營養(yǎng)餐補(bǔ)補(bǔ)腦");
}
public void sleep() {
System.out.println("帶著夢(mèng)想睡覺");
}
public void doSomething() {
System.out.println("認(rèn)真讀書");
}
}
public class ProgramerDaily extends AbstractDaily {
public void eat() {
System.out.println("吃著不是那么友好的外賣");
}
public void sleep() {
System.out.println("睡覺的時(shí)候想著什么時(shí)候身邊會(huì)有一個(gè)她");
}
public void doSomething() {
System.out.println("想要一個(gè)她不是很容易么浸船,自己 new 一個(gè)");
}
}
public class DailyClient {
public static void main(Stringp[] args) {
Daily studentDaily = new StudentDaily();
studentDaily.doSomething();
Daily programerDaily = new ProgramerDaily();
programerDaily.doSomething();
}
}
一個(gè) strategy 模式的簡單實(shí)現(xiàn)
public interface IDaily {
public abstract void eat();
public abstract void sleep();
public abstract void doSomething();
}
public class StudentDaily implements IDaily {
public void eat() {
System.out.println("吃點(diǎn)營養(yǎng)餐補(bǔ)補(bǔ)腦");
}
public void sleep() {
System.out.println("帶著夢(mèng)想睡覺");
}
public void doSomething() {
System.out.println("認(rèn)真讀書");
}
}
public class ProgramerDaily implements IDaily {
public void eat() {
System.out.println("吃著不是那么友好的外賣");
}
public void sleep() {
System.out.println("睡覺的時(shí)候想著什么時(shí)候身邊會(huì)有一個(gè)她");
}
public void doSomething() {
System.out.println("想要一個(gè)她不是很容易么妄迁,自己 new 一個(gè)");
}
}
public class MyDaily {
private IDaily daily;
public MyDaily(IDaily daily) {
this.daily = daily;
}
public void myDaily() {
daily.eat();
daily.doSomething();
daily.sleep();
}
}
public class DailyClient {
public static void main(Stringp[] args) {
MyDaily myDaily = new MyDaily();
myDaily.myDaily();
}
}
結(jié)合上面的代碼解釋兩種模式
在 AbstractDaily 和 MyDaily 中都有一個(gè) myDaily
方法寝蹈,這個(gè) myDaily 方法描述了一個(gè)人的日常:eat
(吃)、doSomething
(活動(dòng))和sleep
(睡覺)登淘。這個(gè) myDaily 封裝了一個(gè)人的日常箫老,也就相當(dāng)于一個(gè)通用算法
。template method 模式和 strategy 都能很好的實(shí)現(xiàn) myDaily 這個(gè)算法形帮,但實(shí)現(xiàn) myDaily 需要調(diào)用的抽象方法[eat()槽惫、 sleep()和 doSomething()]
的方式不一樣周叮。
- template method 是通過
繼承
辩撑,讓子類去實(shí)現(xiàn) eat()、 sleep()和 doSomething()仿耽。 - strategy 將 eat()合冀、 sleep()和 doSomething() 的實(shí)現(xiàn)
委托
給了 IDaily 和它的實(shí)現(xiàn)類。
小結(jié)
template method 模式和 strategy 模式都實(shí)現(xiàn)了對(duì)高層算法和底層具體實(shí)現(xiàn)的分離项贺,都允許高層的算法獨(dú)立于它的具體實(shí)現(xiàn)細(xì)節(jié)重用君躺。
盡管 template method 模式允許一個(gè)通用算法操縱多個(gè)可能的具體實(shí)現(xiàn),但是由于 strategy 模式完全遵循 DIP 原則开缎,從而允許每個(gè)具體實(shí)現(xiàn)都可以被多個(gè)不同的通用算法操縱棕叫。
strategy 模式雖然允許具體實(shí)現(xiàn)細(xì)節(jié)獨(dú)立于高層的算法重用,不過要一些額外的復(fù)雜性奕删、內(nèi)存以及運(yùn)行時(shí)間開銷作為代價(jià)俺泣。
參考
- TEMPLATE METHOD 模式
- STRATEGY 模式
FACADE(外觀) 模式和 MEDIATOR(中介者) 模式
facade 模式
-
簡介
facade 模式定義了一個(gè)
高層接口
,這個(gè)高層接口封裝了子系統(tǒng)的一組接口調(diào)用
完残》疲客戶端無需知道子系統(tǒng)中的復(fù)雜接口調(diào)用關(guān)系,只需要調(diào)用高層接口就好了谨设。 -
使用場(chǎng)景
- 為復(fù)雜的模塊或子系統(tǒng)提供外界訪問的模塊熟掂。
- 子系統(tǒng)相對(duì)獨(dú)立。
- 預(yù)防低水平人員帶來的風(fēng)險(xiǎn)扎拣。
-
優(yōu)點(diǎn)
- 減少系統(tǒng)相互依賴赴肚。
- 提高靈活性。
- 提高了安全性二蓝。
-
缺點(diǎn)
- 不符合開閉原則誉券,如果要改東西很麻煩,繼承重寫都不合適侣夷。
-
注意事項(xiàng)
- 在層次化結(jié)構(gòu)中横朋,可以使用外觀模式定義系統(tǒng)中每一層的入口。
mediator 模式
-
簡介
中介者模式(Mediator Pattern)是用來降低多個(gè)對(duì)象和類之間的通信復(fù)雜性百拓。這種模式提供了一個(gè)中介類琴锭,該類通常處理不同類之間的通信晰甚,并支持松耦合,使代碼易于維護(hù)决帖。中介者模式屬于行為型模式厕九。
-
使用場(chǎng)景
- 系統(tǒng)中對(duì)象之間存在比較復(fù)雜的引用關(guān)系,導(dǎo)致它們之間的依賴關(guān)系結(jié)構(gòu)混亂而且難以復(fù)用該對(duì)象地回。
- 想通過一個(gè)中間類來封裝多個(gè)類中的行為扁远,而又不想生成太多的子類。
-
優(yōu)點(diǎn)
- 降低了類的復(fù)雜度刻像,將一對(duì)多轉(zhuǎn)化成了一對(duì)一畅买。
- 各個(gè)類之間的解耦。
- 符合迪米特原則细睡。
-
缺點(diǎn)
- 中介者會(huì)龐大谷羞,變得復(fù)雜難以維護(hù)。
-
注意事項(xiàng)
- 不應(yīng)當(dāng)在職責(zé)混亂的時(shí)候使用溜徙。
參考
-
FACADE 模式
-
MEDIATOR 模式(中介者模式)
SINGLETON 模式和 MONOSTATE 模式
在一些程序中湃缎,我們需要一些基礎(chǔ)類只能有一個(gè)對(duì)象,例如:用于創(chuàng)建系統(tǒng)其它對(duì)象的工廠類蠢壹。singleton 模式和 monostate 模式就是能夠?qū)崿F(xiàn)強(qiáng)制對(duì)象單一性的兩種方式嗓违。
- singleton 是通過將構(gòu)造函數(shù)私有化,提供一個(gè) static 方法獲取實(shí)例(
對(duì)象只會(huì)被創(chuàng)建一次
)的方式來實(shí)現(xiàn)對(duì)象的單一性图贸。 - monostate 沒有構(gòu)造函數(shù)私有化蹂季,你可以創(chuàng)建多個(gè) monostate 對(duì)象。但是 monostate 中的
所有屬性是 static
的求妹。那么乏盐,不論你創(chuàng)建多少個(gè) monostate 對(duì)象,它們的屬性都是相同的制恍,因此實(shí)現(xiàn)了對(duì)象的單一性父能。
一個(gè)簡單的 singleton 實(shí)現(xiàn)
public class SingleTon {
private static SingleTon instance = null;
private SingleTon() {}
public static SingleTon getInstance() {
if (instance == null) {
return new SingleTon();
}
return instance;
}
}
一個(gè)簡單的 monostate 實(shí)現(xiàn)
public class Monostate {
private static String name;
public Monostate() {}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
singleton 模式的優(yōu)缺點(diǎn)
-
優(yōu)點(diǎn)
- 跨平臺(tái):使用合適的中間件(例如:RMI),可以把 singleton 模式擴(kuò)展為多個(gè) JVM 和多個(gè)計(jì)算機(jī)工作净神。
- 適用于任何類:只需把一個(gè)類的構(gòu)造函數(shù)變成私有的何吝,并且在其中增加相應(yīng)的靜態(tài)函數(shù)和變量,就可以把這個(gè)類變?yōu)?singleton鹃唯。
- 可以通過派生創(chuàng)建:給定一個(gè)類爱榕,可以創(chuàng)建它的一個(gè) singleton 子類。
- 延遲求值:如果 singleton 從未使用過坡慌,那么就不會(huì)創(chuàng)建它黔酥。
-
缺點(diǎn)
- 摧毀方式未定義:沒有好的方法去摧毀一個(gè) singleton,或者解除其職責(zé)。即使添加一個(gè) decommission 方法把 instance 置為 null跪者,系統(tǒng)中其它模塊仍然持有該對(duì)象實(shí)例的引用棵帽。
- 不能繼承:從 singleton 類派生出來的類并不是 singleton。如果要使其成為 singleton渣玲,必須要增加所需的靜態(tài)函數(shù)和變量逗概。
- 效率問題:每次調(diào)用 getInstance 方法都會(huì)執(zhí)行 if 語句,就大多數(shù)調(diào)用而言忘衍,if 語句是多余的逾苫。
- 不透明性:singleton 的使用者知道他們?cè)谑褂靡粋€(gè) singleton,因?yàn)樗麄儽仨氁{(diào)用 getInstance 方法枚钓。
monostate 模式的優(yōu)缺點(diǎn)
-
優(yōu)點(diǎn)
- 透明性:使用 monostate 對(duì)象使用常規(guī)對(duì)象沒有什么區(qū)別铅搓。使用者不需要知道對(duì)象是 monostate。
- 可派生性:monostate 的派生類都是 monostate秘噪。事實(shí)上狸吞,monostate 的所有派生類都是同一個(gè) monostate 的一部分勉耀。他們共享相同的靜態(tài)變量指煎。
- 多態(tài)性:由于 monostate 的方法不是靜態(tài)的,所以可以在派生類中復(fù)寫他們便斥。因此至壤,不同的派生類可以基于同樣的靜態(tài)變量表現(xiàn)出不同的行為。
-
缺點(diǎn)
- 不可轉(zhuǎn)換性:不能透過派生把常規(guī)類轉(zhuǎn)換成 monostate 類枢纠。
- 效率問題:因?yàn)?monostate 是真正的對(duì)象像街,所以會(huì)導(dǎo)致許多的創(chuàng)建和摧毀開銷。
- 內(nèi)存占用:即使從未使用 monostate晋渺,它的變量也要占內(nèi)存空間镰绎。
- 平臺(tái)局限性:monostate 不能跨多個(gè) JVM 或者多個(gè)平臺(tái)工作。
如何選擇 singleton 與 monostate
如果希望通過派生去約束一個(gè)現(xiàn)存類木西,并且不介意它的所有調(diào)用者都必須調(diào)用 getInstance 方法來獲取訪問畴栖,那么 singleton 是最合適的。
如果希望類的單一性本質(zhì)對(duì)使用者透明八千,或者希望使用單一對(duì)象的多態(tài)派生對(duì)象吗讶,那么 monostate 是最合適的。
參考
- https://www.cnblogs.com/hibernate6/archive/2012/01/11/2521954.html
- https://blog.csdn.net/nirvana_li/article/details/1449126
NULL OBJECT 模式
為什么需要 null object 模式
Employee e = DB.getEmployeeByName("Peter");
if (e != null) {
System.out.println(e.getName());
}
我們通常從其它方法獲取一個(gè)對(duì)象后恋捆,會(huì)編寫與上面類似的代碼照皆,我們需要對(duì)獲取的對(duì)象進(jìn)行 null 檢查,如果不進(jìn)行檢查直接使用的話很可能會(huì)出現(xiàn)空指針異常沸停。因?yàn)槲覀儧]辦法保證我們從別處獲得對(duì)象一定是非空的膜毁。
如果代碼中到處充斥著 null 檢查,代碼會(huì)非常丑陋,所以就有了 null object 模式瘟滨。
null object 模式的簡單實(shí)現(xiàn)
-
先定義一個(gè)接口 IEmployee
public interface IEmployee { boolean isNull(); String getName(); }
-
接著定義一個(gè)實(shí)現(xiàn) IEmployee 接口的具體類 AlibabaEmloyee
public class AlibabaEmloyee implements IEmployee { @Override public boolean isNull() { return false; } @Override public String getName() { return "name"; } }
-
然后定義一個(gè)實(shí)現(xiàn) IEmployee 接口的空類 NullEmloyee
public class NullEmloyee implements IEmployee { @Override public boolean isNull() { return true; } @Override public String getName() { return ""; } }
-
緊接著編寫一個(gè) DB 類
public class DB { public static IEmployee getEmployeeByName(String name) { if ("Peter".equals(name)) { return new NullEmployee(); } return new AlibabaEmployee(); } }
-
最后編寫一個(gè)測(cè)試代碼
public class Test { public static void main(String[] args) { IEmployee e = DB.getEmployeeByName("Peter"); System.out.println(e.getName()); } }
在測(cè)試代碼中葬凳,我們不再需要對(duì) IEmployee 對(duì)象進(jìn)行 null 檢查,NullEmployee 替代了 null室奏。
null object 模式的不足
雖然 null object 模式比直接進(jìn)行 null 檢查要優(yōu)雅火焰,但需要額外編寫大量的輔助類,我門需要為一個(gè)類創(chuàng)建一個(gè)接口和一個(gè)空類胧沫,這使得代碼非常臃腫昌简。還有其它可以優(yōu)雅處理 null 的方法,請(qǐng)參考這篇文章绒怨。