热门问题
时间线
聊天
视角

命令模式

来自维基百科,自由的百科全书

命令模式
Remove ads

物件導向程式設計的範疇中,命令模式(英語:Command pattern),是一種行為型設計模式,它是用來封裝以後某個時間進行的一個動作或觸發一個事件的所有信息的一個對象。這些信息包括方法名字,擁有這個方法的對象和給這個方法諸參數的諸值[1]

Thumb
命令模式的UML類圖

概述

使用命令對象,可以更容易的構造以通用構件,用來在其選定的時間,委託、序列或執行方法調用,而不需要知道這個方法的類或者這個方法的諸參數。使用調用者(invoker)對象,允許方便進行對命令執行的簿記,還有為命令實現不同的模態(mode),這是由調用者對象管理的,不需要讓客戶知曉簿記或模態的存在。

這個設計模式的中心想法,是緊密鏡像函數式編程語言中的頭等函數高階函數的語義。尤其調用者對象是高階函數,而命令對象是其頭等實際參數。

結構

Thumb
命令模式的樣例UML類圖和序列圖[2]

在上面的UML類圖中,Invoker類不直接實現一個請求。Invoker轉而提及到Command接口,通過它來辦理一個請求(command.execute()),這使得Invoker獨立於這些請求的辦理者。Command1類實現了Command接口,它在一個接收者(receiver1.action1())上施行一個動作。此外,客戶Client創建具體命令類比如Command1的對象並設置它的接收者。

UML序列圖展示了運行時交互:Invoker對象調用execute()Command1對象之上。Command1調用action1()在一個Receiver1對象之上,它辦理這個請求。

範例

Java

下面是Java例子:

import java.util.List;
import java.util.ArrayList;

/* The Command interface */
public interface Command {
    void execute();
}

/* The Invoker class */
public class Switch {
    private List<Command> history = new ArrayList<Command>();

    public Switch() {
    }

    public void storeAndExecute(Command cmd) {
        this.history.add(cmd); // optional 
        cmd.execute();        
    }
}

/* The Receiver class */
public class Light {
    public Light() {
    }

    public void turnOn() {
        System.out.println("The light is on");
    }

    public void turnOff() {
        System.out.println("The light is off");
    }
}

/* The Command for turning on the light - ConcreteCommand #1 */
public class FlipUpCommand implements Command {
    private Light theLight;

    public FlipUpCommand(Light light) {
        this.theLight = light;
    }

    public void execute(){
        theLight.turnOn();
    }
}

/* The Command for turning off the light - ConcreteCommand #2 */
public class FlipDownCommand implements Command {
    private Light theLight;

    public FlipDownCommand(Light light) {
        this.theLight = light;
    }

    public void execute() {
        theLight.turnOff();
    }
}

/* The test class or client */
public class PressSwitch {
    public static void main(String[] args){
        Light lamp = new Light();
        Command switchUp = new FlipUpCommand(lamp);
        Command switchDown = new FlipDownCommand(lamp);

        Switch mySwitch = new Switch();

        try {
            if ("ON".equalsIgnoreCase(args[0])) {
                mySwitch.storeAndExecute(switchUp);
            }
            else if ("OFF".equalsIgnoreCase(args[0])) {
                mySwitch.storeAndExecute(switchDown);
            }
            else {
                System.out.println("Argument \"ON\" or \"OFF\" is required.");
            }
        } catch (Exception e) {
            System.out.println("Arguments required.");
        }
    }
}
Remove ads

C#

下面是C#例子:

using System;
using System.Collections.Generic;

namespace CommandPattern {
    public interface ICommand {
        void Execute();
    }

    /* The Invoker class */
    public class Switch {
        private List<ICommand> _commands = new List<ICommand>();

        public void StoreAndExecute(ICommand command) {
            _commands.Add(command);
            command.Execute();
        }
    }

    /* The Receiver class */
    public class Light {
        public void TurnOn() {
            Console.WriteLine("The light is on");
        }

        public void TurnOff() {
            Console.WriteLine("The light is off");
        }
    }

    /* The Command for turning on the light - ConcreteCommand #1 */
    public class FlipUpCommand : ICommand {
        private Light _light;

        public FlipUpCommand(Light light) {
            _light = light;
        }

        public void Execute() {
            _light.TurnOn();
        }
    }

    /* The Command for turning off the light - ConcreteCommand #2 */
    public class FlipDownCommand : ICommand {
        private Light _light;

        public FlipDownCommand(Light light) {
            _light = light;
        }

        public void Execute() {
            _light.TurnOff();
        }
    }

    /* The test class or client */
    internal class Program {
        public static void Main(string[] args) {
            Light lamp = new Light();
            ICommand switchUp = new FlipUpCommand(lamp);
            ICommand switchDown = new FlipDownCommand(lamp);

            Switch s = new Switch();
            string arg = args.Length > 0 ? args[0].ToUpper() : null;
            if (arg == "ON") {
                s.StoreAndExecute(switchUp);
            }
            else if (arg == "OFF") {
                s.StoreAndExecute(switchDown);
            }
            else {
                Console.WriteLine("Argument \"ON\" or \"OFF\" is required.");
            }
        }
    }
}
Remove ads

Python

下面是Python例子:

from abc import ABC, abstractmethod

class Light():
    def turn_on(self):
        print("The light is on")
    def turn_off(self):
        print("The light is off")   

class Command(ABC):
    @abstractmethod
    def __call__(self): pass

class FlipUpCommand(Command):
    def __init__(self, light):
        self.__light = light
    def __call__(self):
        self.__light.turn_on()
        
class FlipDownCommand(Command):
    def __init__(self, light):
        self.__light = light
    def __call__(self):
        self.__light.turn_off()

class Switch():
    def __init__(self):
        self.history = []   
    def __call__(self, cmd):
        assert isinstance(cmd, Command)
        self.history += [type(cmd).__name__]
        cmd()

class PressSwitch():
    def __init__(self):
        lamp = Light()
        self.__switch_up = FlipUpCommand(lamp)
        self.__switch_down = FlipDownCommand(lamp)
        self.__switch = Switch() 
    def __call__(self, cmd):
        cmd = cmd.strip().upper()
        if cmd == "ON":
            self.__switch(self.__switch_up)
        elif cmd == "OFF":
            self.__switch(self.__switch_down)
        else:
            print("Argument 'On' or 'Off' is required.")

其執行:

>>> press_switch = PressSwitch()
>>> press_switch("On")
The light is on
>>> press_switch("Off")
The light is off
>>> press_switch("ThirdState")
Argument 'On' or 'Off' is required.
Remove ads

Javascript

下面是Javascript例子:

/* The Invoker function */
var Switch = function(){
    var _commands = [];
    this.storeAndExecute = function(command){
        _commands.push(command);
        command.execute();
    }
}

/* The Receiver function */
var Light = function(){
    this.turnOn = function(){ console.log ('turn on')};
    this.turnOff = function(){ console.log ('turn off') };
}

/* The Command for turning on the light - ConcreteCommand #1 */
var FlipUpCommand = function(light){
    this.execute = light.turnOn;
}

/* The Command for turning off the light - ConcreteCommand #2 */
var FlipDownCommand = function(light){
    this.execute = light.turnOff;
}

var light = new Light();
var switchUp = new FlipUpCommand(light);
var switchDown = new FlipDownCommand(light);
var s = new Switch();

s.storeAndExecute(switchUp);
s.storeAndExecute(switchDown);
Remove ads

C++

下面是基於《設計模式》書中前C++98實現的C++23實現例子:

import std;

using std::shared_ptr;
using std::unique_ptr;

// Abstract command
class Command {
protected:
    Command() = default;
public:
    // declares an interface for executing an operation.
    virtual void execute() = 0;
    virtual ~Command() = default;
};

// Concrete command
template <typename Receiver>
class SimpleCommand : public Command {
private:
    Receiver* receiver;
    Action action;
public:
    using Action = void (Receiver::*)();

    // defines a binding between a Receiver object and an action.
    SimpleCommand(shared_ptr<Receiver> receiver, Action action):
        receiver{receiver.get()}, action{action} {}

    SimpleCommand(const SimpleCommand&) = delete;
    const SimpleCommand& operator=(const SimpleCommand&) = delete;

    // implements execute by invoking the corresponding operation(s) on Receiver.
    virtual void execute() {
        (receiver->*action)();
    }
};

// Receiver
class MyClass {
public:
    // knows how to perform the operations associated with carrying out a request. Any class may serve as a Receiver.
    void action() {
        std::println("MyClass::action called");
    }
};

int main(int argc, char* argv[]) {
    shared_ptr<MyClass> receiver = std::make_shared<MyClass>();
    // ...
    unique_ptr<Command> command = std::make_unique<SimpleCommand<MyClass>>(receiver, &MyClass::action);
    // ...
    command->execute();
}

程序輸出為:

MyClass::action called
Remove ads

引用

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.

Remove ads