作者公眾號:一角錢技術(org_yijiaoqian)
前言
23種設計模式速記
單例(singleton)模式
工廠方法(factory method)模式
抽象工廠(abstract factory)模式
建造者/構建器(builder)模式
原型(prototype)模式
享元(flyweight)模式
外觀(facade)模式
介面卡(adapter)模式
裝飾(decorator)模式
觀察者(observer)模式
策略(strategy)模式
橋接(bridge)模式
模版方法(template method)模式
責任鏈(chain of responsibility)模式
組合(composite)模式
代理(proxy)模式
備忘錄(memento)模式
持續更新中
……
23種設計模式快速記憶的請看上面第一篇,本篇和大家一起來學習
命令模式
相關內容。
模式定義
將一個請求封裝為一個物件,使發出請求的責任和執行請求的責任分割開。這樣兩者之間透過命令物件進行溝通,這樣方便將命令物件進行儲存、傳遞、呼叫、增加與管理。
在軟體開發系統中,常常出現“方法的請求者”與“方法的實現者”之間存在緊密的耦合關係。這不利於軟體功能的擴充套件與維護。例如,想對行為進行“撤銷、重做、記錄”等處理都很不方便,因此“如何將方法的請求者與方法的實現者解耦?”變得很重要,命令模式能很好地解決這個問題。
模版實現如下
:
package com。niuh。designpattern。command。v1;/** *
* 命令模式 *
*/public class CommandPattern { public static void main(String[] args) { Command cmd = new ConcreteCommand(); Invoker ir = new Invoker(cmd); System。out。println(“客戶訪問呼叫者的call()方法。。。”); ir。call(); }}//抽象命令interface Command { public abstract void execute();}//具體命令class ConcreteCommand implements Command { private Receiver receiver; ConcreteCommand() { receiver = new Receiver(); } public void execute() { receiver。action(); }}//接收者class Receiver { public void action() { System。out。println(“接收者的action()方法被呼叫。。。”); }}//呼叫者class Invoker { private Command command; public Invoker(Command command) { this。command = command; } public void setCommand(Command command) { this。command = command; } public void call() { System。out。println(“呼叫者執行命令command。。。”); command。execute(); }}輸出結果如下
:
客戶訪問呼叫者的call()方法。。。呼叫者執行命令command。。。接收者的action()方法被呼叫。。。
解決的問題
在軟體系統中,行為請求者與行為實現者通常是一種緊耦合的關係,但某些場合,比如需要對行為進行記錄、撤銷或重做、事務等處理時,這種無法抵禦變化的緊耦合的設計就不太合適。
模式組成
可以將系統中的相關操作抽象成命令,使呼叫者與實現者相關分離,其結構如下。
例項說明
例項概況
結合命令模式,實現一個課程影片的開啟和關閉。
使用步驟
步驟1
:宣告執行命令的介面,擁有執行命令的抽象方法 execute()
interface Command { void execute();}
步驟2
:定義具體命令角色,建立開啟課程連結 和 關閉課程連線
/** * 開啟課程連結 */class OpenCourseVideoCommand implements Command { private CourseVideo courseVideo; public OpenCourseVideoCommand(CourseVideo courseVideo) { this。courseVideo = courseVideo; } @Override public void execute() { courseVideo。open(); }}/** * 關閉課程連結 */class CloseCourseVideoCommand implements Command { private CourseVideo courseVideo; public CloseCourseVideoCommand(CourseVideo courseVideo) { this。courseVideo = courseVideo; } @Override public void execute() { courseVideo。close(); }}
步驟3
:定義接收者角色,執行命令功能的相關操作,是具體命令物件業務的真正實現者
class CourseVideo { private String name; public CourseVideo(String name) { this。name = name; } public void open() { System。out。println(this。name + “課程影片開放。”); } public void close() { System。out。println(this。name + “課程影片關閉。”); }}
步驟4
:建立User物件為請求的傳送者,即請求者角色
class User { private List
步驟4
:測試執行
public class CommandPattern { public static void main(String[] args) { //命令接收者 CourseVideo courseVideo = new CourseVideo(“設計模式系列”); //建立命令 OpenCourseVideoCommand openCourseVideoCommand = new OpenCourseVideoCommand(courseVideo); CloseCourseVideoCommand closeCourseVideoCommand = new CloseCourseVideoCommand(courseVideo); //建立執行人 User user = new User(); //新增命令 user。addCommand(openCourseVideoCommand); user。addCommand(closeCourseVideoCommand); //執行 user。executeCommands(); }}
輸出結果
設計模式系列課程影片開放。設計模式系列課程影片關閉。
優點
降低系統的耦合度。命令模式能將呼叫操作的物件與實現該操作的物件解耦。
增加或刪除命令非常方便。採用命令模式增加與刪除命令不會影響其他類,它滿足“開閉原則”,對擴充套件比較靈活。
可以實現宏命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即宏命令。
方便實現 Undo 和 Redo 操作。命令模式可以與後面介紹的備忘錄模式結合,實現命令的撤銷與恢復。
缺點
可能產生大量具體命令類。因為計對每一個具體操作都需要設計一個具體命令類,這將增加系統的複雜性。
應用場景
命令執行過程較為複雜且可能存在變化,需要對執行命令動作本身進行額外操作,此時可以考慮使用命令模式
命令模式的擴充套件
在軟體開發中,有時將命令模式與組合模式聯合使用,這就構成了宏命令模式,也叫組合命令模式。宏命令包含了一組命令,它充當了具體命令與呼叫者的雙重角色,執行它時將遞迴呼叫它所包含的所有命令,其具體結構圖如下:
模版實現如下
:
package com。niuh。designpattern。command。v2;import java。util。ArrayList;/** *
* 組合命令模式 *
*/public class CompositeCommandPattern { public static void main(String[] args) { AbstractCommand cmd1 = new ConcreteCommand1(); AbstractCommand cmd2 = new ConcreteCommand2(); CompositeInvoker ir = new CompositeInvoker(); ir。add(cmd1); ir。add(cmd2); System。out。println(“客戶訪問呼叫者的execute()方法。。。”); ir。execute(); }}//抽象命令interface AbstractCommand { public abstract void execute();}//樹葉構件: 具體命令1class ConcreteCommand1 implements AbstractCommand { private CompositeReceiver receiver; ConcreteCommand1() { receiver = new CompositeReceiver(); } public void execute() { receiver。action1(); }}//樹葉構件: 具體命令2class ConcreteCommand2 implements AbstractCommand { private CompositeReceiver receiver; ConcreteCommand2() { receiver = new CompositeReceiver(); } public void execute() { receiver。action2(); }}//樹枝構件: 呼叫者class CompositeInvoker implements AbstractCommand { private ArrayList輸出結果如下
:
客戶訪問呼叫者的execute()方法。。。接收者的action1()方法被呼叫。。。接收者的action2()方法被呼叫。。。
命令模式還可以同備忘錄(Memento)模式組合使用,這樣就變成了可撤銷的命令模式
原始碼中的應用
java。util。Timer類中scheduleXXX()方法
java Concurrency Executor execute() 方法
java。lang。reflect。Method invoke()方法
org。springframework。jdbc。core。JdbcTemplate
……
在 JdbcTemplate 中的應用
在JdbcTemplate中命令模式的使用並沒有遵從標準的命令模式的使用,只是思想相同而已。
在 Spring 的 JdbcTemplate 這個類中有 query() 方法,query() 方法中定義了一個內部類 QueryStatementCallback,QueryStatementCallback 又實現了 StatementCallback 介面,另外還有其它類實現了該介面,StatementCallback 介面中又有一個抽象方法 doInStatement()。在 execute() 中又呼叫了 query()。
StatementCallback
充當的是命令角色,
JdbcTemplate
即充當呼叫者角色,又充當接收者角色。上面的類圖只是為了方便理解,實際上,QueryStatementCallback 與 ExecuteStatementCallback是JdbcTemplate中方法的內部類,具體看原始碼中的內容。
部分原始碼分析
StatementCallback介面:
public interface StatementCallback
JdbcTemplate類:
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { //相當於呼叫者釋出的一個命令 @Override public
PS
:以上程式碼提交在
Github
:
https://github。com/Niuh-Study/niuh-designpatterns。git
文章持續更新,可以公眾號搜一搜「
一角錢技術
」第一時間閱讀, 本文 GitHub
org_hejianhui/JavaStudy
已經收錄,歡迎 Star。