<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          命令模式

          共 8028字,需瀏覽 17分鐘

           ·

          2021-12-19 12:01

          在軟件開發(fā)系統(tǒng)中,“方法的請求者”與“方法的實現者”之間經常存在緊密的耦合關系,這不利于軟件功能的擴展與維護。例如,想對方法進行“撤銷、重做、記錄”等處理都很不方便,因此“如何將方法的請求者與實現者解耦?”變得很重要,命令模式就能很好地解決這個問題。

          在現實生活中,命令模式的例子也很多。比如看電視時,我們只需要輕輕一按遙控器就能完成頻道的切換,這就是命令模式,將換臺請求和換臺處理完全解耦了。電視機遙控器(命令發(fā)送者)通過按鈕(具體命令)來遙控電視機(命令接收者)。

          再比如,我們去餐廳吃飯,菜單不是等到客人來了之后才定制的,而是已經預先配置好的。這樣,客人來了就只需要點菜,而不是任由客人臨時定制。餐廳提供的菜單就相當于把請求和處理進行了解耦,這就是命令模式的體現。

          命令模式的定義與特點

          命令(Command)模式的定義如下:將一個請求封裝為一個對象,使發(fā)出請求的責任和執(zhí)行請求的責任分割開。這樣兩者之間通過命令對象進行溝通,這樣方便將命令對象進行儲存、傳遞、調用、增加與管理。

          命令模式的主要優(yōu)點如下。

          1. 通過引入中間件(抽象接口)降低系統(tǒng)的耦合度。

          2. 擴展性良好,增加或刪除命令非常方便。采用命令模式增加與刪除命令不會影響其他類,且滿足“開閉原則”。

          3. 可以實現宏命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即宏命令。

          4. 方便實現 Undo 和 Redo 操作。命令模式可以與后面介紹的備忘錄模式結合,實現命令的撤銷與恢復。

          5. 可以在現有命令的基礎上,增加額外功能。比如日志記錄,結合裝飾器模式會更加靈活。


          其缺點是:

          1. 可能產生大量具體的命令類。因為每一個具體操作都需要設計一個具體命令類,這會增加系統(tǒng)的復雜性。

          2. 命令模式的結果其實就是接收方的執(zhí)行結果,但是為了以命令的形式進行架構、解耦請求與實現,引入了額外類型結構(引入了請求方與抽象命令接口),增加了理解上的困難。不過這也是設計模式的通病,抽象必然會額外增加類的數量,代碼抽離肯定比代碼聚合更加難理解。

          命令模式的結構與實現

          可以將系統(tǒng)中的相關操作抽象成命令,使調用者與實現者相關分離,其結構如下。

          1. 模式的結構

          命令模式包含以下主要角色。

          1. 抽象命令類(Command)角色:聲明執(zhí)行命令的接口,擁有執(zhí)行命令的抽象方法 execute()。

          2. 具體命令類(Concrete Command)角色:是抽象命令類的具體實現類,它擁有接收者對象,并通過調用接收者的功能來完成命令要執(zhí)行的操作。

          3. 實現者/接收者(Receiver)角色:執(zhí)行命令功能的相關操作,是具體命令對象業(yè)務的真正實現者。

          4. 調用者/請求者(Invoker)角色:是請求的發(fā)送者,它通常擁有很多的命令對象,并通過訪問命令對象來執(zhí)行相關請求,它不直接訪問接收者。


          其結構圖如圖 1 所示。

          圖1 命令模式的結構圖

          2. 模式的實現

          命令模式的代碼如下:

          package command;
          public class CommandPattern { public static void main(String[] args) { Command cmd = new ConcreteCommand(); Invoker ir = new Invoker(cmd); System.out.println("客戶訪問調用者的call()方法..."); ir.call(); }}
          //調用者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("調用者執(zhí)行命令command..."); command.execute(); }}
          //抽象命令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()方法被調用..."); }}

          程序的運行結果如下:

          客戶訪問調用者的call()方法...
          調用者執(zhí)行命令command...
          接收者的action()方法被調用...

          命令模式的應用實例

          【例1】用命令模式實現客戶去餐館吃早餐的實例。

          分析:客戶去餐館可選擇的早餐有腸粉、河粉和餛飩等,客戶可向服務員選擇以上早餐中的若干種,服務員將客戶的請求交給相關的廚師去做。這里的點早餐相當于“命令”,服務員相當于“調用者”,廚師相當于“接收者”,所以用命令模式實現比較合適。

          • 首先,定義一個早餐類(Breakfast),它是抽象命令類,有抽象方法 cooking(),說明要做什么;

          • 再定義其子類腸粉類(ChangFen)、餛飩類(HunTun)和河粉類(HeFen),它們是具體命令類,實現早餐類的 cooking() 方法,但它們不會具體做,而是交給具體的廚師去做;

          • 具體廚師類有腸粉廚師(ChangFenChef)、餛飩廚師(HunTunChef)和河粉廚師(HeFenChef),他們是命令的接收者。


          由于本實例要顯示廚師做菜的效果圖,所以把每個廚師類定義為 JFrame 的子類;最后,定義服務員類(Waiter),它接收客戶的做菜請求,并發(fā)出做菜的命令。客戶類是通過服務員類來點菜的,圖 2 所示是其結構圖。

          圖2 客戶在餐館吃早餐的結構圖


          程序代碼如下:

          package command;
          import javax.swing.*;
          public class CookingCommand { public static void main(String[] args) { Breakfast food1 = new ChangFen(); Breakfast food2 = new HunTun(); Breakfast food3 = new HeFen(); Waiter fwy = new Waiter(); fwy.setChangFen(food1);//設置腸粉菜單 fwy.setHunTun(food2); //設置河粉菜單 fwy.setHeFen(food3); //設置餛飩菜單 fwy.chooseChangFen(); //選擇腸粉 fwy.chooseHeFen(); //選擇河粉 fwy.chooseHunTun(); //選擇餛飩 }}
          //調用者:服務員class Waiter { private Breakfast changFen, hunTun, heFen;
          public void setChangFen(Breakfast f) { changFen = f; }
          public void setHunTun(Breakfast f) { hunTun = f; }
          public void setHeFen(Breakfast f) { heFen = f; }
          public void chooseChangFen() { changFen.cooking(); }
          public void chooseHunTun() { hunTun.cooking(); }
          public void chooseHeFen() { heFen.cooking(); }}
          //抽象命令:早餐interface Breakfast { public abstract void cooking();}
          //具體命令:腸粉class ChangFen implements Breakfast { private ChangFenChef receiver;
          ChangFen() { receiver = new ChangFenChef(); }
          public void cooking() { receiver.cooking(); }}
          //具體命令:餛飩class HunTun implements Breakfast { private HunTunChef receiver;
          HunTun() { receiver = new HunTunChef(); }
          public void cooking() { receiver.cooking(); }}
          //具體命令:河粉class HeFen implements Breakfast { private HeFenChef receiver;
          HeFen() { receiver = new HeFenChef(); }
          public void cooking() { receiver.cooking(); }}
          //接收者:腸粉廚師class ChangFenChef extends JFrame { private static final long serialVersionUID = 1L; JLabel l = new JLabel();
          ChangFenChef() { super("煮腸粉"); l.setIcon(new ImageIcon("src/command/ChangFen.jpg")); this.add(l); this.setLocation(30, 30); this.pack(); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
          public void cooking() { this.setVisible(true); }}
          //接收者:餛飩廚師class HunTunChef extends JFrame { private static final long serialVersionUID = 1L; JLabel l = new JLabel();
          HunTunChef() { super("煮餛飩"); l.setIcon(new ImageIcon("src/command/HunTun.jpg")); this.add(l); this.setLocation(350, 50); this.pack(); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
          public void cooking() { this.setVisible(true); }}
          //接收者:河粉廚師class HeFenChef extends JFrame { private static final long serialVersionUID = 1L; JLabel l = new JLabel();
          HeFenChef() { super("煮河粉"); l.setIcon(new ImageIcon("src/command/HeFen.jpg")); this.add(l); this.setLocation(200, 280); this.pack(); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
          public void cooking() { this.setVisible(true); }}

          程序的運行結果如圖 2 所示。

          圖2 客戶在餐館吃早餐的運行結果

          命令模式的應用場景

          當系統(tǒng)的某項操作具備命令語義,且命令實現不穩(wěn)定(變化)時,可以通過命令模式解耦請求與實現。使用抽象命令接口使請求方的代碼架構穩(wěn)定,封裝接收方具體命令的實現細節(jié)。接收方與抽象命令呈現弱耦合(內部方法無需一致),具備良好的擴展性。

          命令模式通常適用于以下場景。

          1. 請求調用者需要與請求接收者解耦時,命令模式可以使調用者和接收者不直接交互。

          2. 系統(tǒng)隨機請求命令或經常增加、刪除命令時,命令模式可以方便地實現這些功能。

          3. 當系統(tǒng)需要執(zhí)行一組操作時,命令模式可以定義宏命令來實現該功能。

          4. 當系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(Redo)操作時,可以將命令對象存儲起來,采用備忘錄模式來實現。

          命令模式的擴展

          在軟件開發(fā)中,有時將命令模式與前面學的組合模式聯合使用,這就構成了宏命令模式,也叫組合命令模式。宏命令包含了一組命令,它充當了具體命令與調用者的雙重角色,執(zhí)行它時將遞歸調用它所包含的所有命令,其具體結構圖如圖 3 所示。

          圖3 組合命令模式的結構圖


          程序代碼如下:

          package command;
          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 children = new ArrayList();
          public void add(AbstractCommand c) { children.add(c); }
          public void remove(AbstractCommand c) { children.remove(c); }
          public AbstractCommand getChild(int i) { return children.get(i); }
          public void execute() { for (Object obj : children) { ((AbstractCommand) obj).execute(); } }}
          //接收者class CompositeReceiver { public void action1() { System.out.println("接收者的action1()方法被調用..."); }
          public void action2() { System.out.println("接收者的action2()方法被調用..."); }}

          程序的運行結果如下:

          客戶訪問調用者的execute()方法...
          接收者的action1()方法被調用...
          接收者的action2()方法被調用...


          當然,命令模式還可以同備忘錄(Memento)模式組合使用,這樣就變成了可撤銷的命令模式,這將在后面介紹。

          原文鏈接:http://c.biancheng.net/view/1380.html

          ——————END——————

          歡迎關注“Java引導者”,我們分享最有價值的Java的干貨文章,助力您成為有思想的Java開發(fā)工程師!

          瀏覽 21
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩一级性爱视频 | 日韩色情视频 | 中国精品黄色视频 | 69视频国产 | 亚洲免费在线看 |