使用Command Design模式

RKC*_*KCY 14 java oop design-patterns command-pattern

任何人都可以用命令模式的简单例子来解释.我在互联网上提到但我很困惑.

Dro*_*roo 20

public interface Command {
   public void execute();
}
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,命令是不可变的,并包含封装按需执行的单个操作的指令.您可能还有一个RuntimeCommand在执行时接受指令,但这会根据实现深入研究策略或装饰器模式.

在我看来,我认为注意命令的不可变上下文非常重要,否则命令就会成为一个建议.例如:

public final class StopServerCommand implements Command {
    private final Server server;

    public StopServerCommand(Server server) { this.server = server; }

    public void execute() {
        if(server.isRunning()) server.stop();
    }
}

public class Application {
    //...
    public void someMethod() {
        stopButton.addActionListener(new ActionListener() {
            public void actionPerformed(Event e) {
                 stopCommand.execute();
            }
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我个人并不喜欢命令.根据我自己的经验,它们只适用于框架回调.

如果它有所帮助,那就想一下隐喻意义上的命令; 训练有素的士兵由他/她的指挥官给予命令,并且根据要求士兵执行该命令.

  • @Droo到底在哪里创建了对象`stopCommand`? (3认同)
  • @Droo,跟进你的"不太喜欢" - 它们实际上是抽象设备控制等事情的非常自然的实现.例如,我曾经使用普通的操纵杆来驱动各种相机(都使用不同的串行协议).有一个"Pan"命令,另一个用于"Zoom"等命令非常有帮助. (2认同)

Rav*_*abu 8

您可以将Command模式工作流视为如下.

客户端调用Invoker => Invoker调用ConcreteCommand => ConcreteCommand调用Receiver方法,该方法实现抽象的Command方法.

来自dofactory文章的UML图:

在此输入图像描述

主要特点:

  1. Command为所有命令声明一个接口,提供一个简单的execute()方法,该方法要求接收器执行命令.

  2. 接收器有怎样做才能执行请求的知识.

  3. 祈求拥有一个命令,可以得到命令通过调用execute方法来执行请求.

  4. 客户端创建ConcreteCommands并设置一个接收器的命令.

  5. 所述的ConcreteCommand定义了动作和接收器之间的结合.

  6. Invoker调用执行时,ConcreteCommand将在Receiver上运行一个或多个操作.

代码段:

interface Command {
    void execute();
}
interface Receiver {
    public  void switchOn();

}
class OnCommand implements Command{
    private Receiver receiver;

    public OnCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        receiver.switchOn();
    }
}
class Invoker {
    private Command command;

    public Invoker(Command command){
        this.command = command;
    }
    public void execute(){
        this.command.execute();
    }
}

class TV implements Receiver{

     public void switchOn(){
        System.out.println("Switch on from TV");
    }
}
class DVDPlayer implements Receiver{

    public void switchOn(){
         System.out.println("Switch on from DVDPlayer");
    }
}

public class CommandDemoEx{
    public static void main(String args[]){
        // On command for TV with same invoker 
        Receiver receiver = new TV();
        Command onCommand = new OnCommand(receiver);
        Invoker invoker = new Invoker(onCommand);
        invoker.execute();

        // On command for DVDPlayer with same invoker 
        receiver = new DVDPlayer();
        onCommand = new OnCommand(receiver);
        invoker = new Invoker(onCommand);
        invoker.execute();            
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Switch on from TV
Switch on from DVDPlayer
Run Code Online (Sandbox Code Playgroud)

说明:

在这个例子中,

  1. 命令接口定义execute()方法.
  2. OnCommandConcreteCommand,它实现了execute()方法.
  3. Receiver是一个接口,实现者必须为这些方法提供实现.
  4. TVDVDPlayer是两种类型的接收器,它们像OnCommand一样传递给ConcreteCommand.
  5. 祈求者包含命令.这是将Sender与Receiver解耦的关键.
  6. Invoker接收OnCommand - >,它调用Receiver(TV)来执行此命令.

通过使用Invoker,您可以打开电视和DVDPlayer.如果您扩展此程序,您也关闭电视和DVDPlayer.

您可以使用命令模式

  1. 解除发送者和接收者的命令

  2. 实现回调机制

  3. 实现撤消和重做功能

  4. 保持命令的历史

看看这个dzonejournaldev以及维基百科的文章.

维基百科页面的源代码简单,清晰,自我解释.

如果您按照本文中引用的步骤操作,则可以实现撤消重做


Sam*_*uel 6

以下是您可以使用真实场景来了解命令模式如何工作的另一个示例:您无法使用命令模式通过飞机从一个地方旅行到另一个地方!

如果您经常旅行,那么您作为客户所关心的一切就是从您到达另一个地方旅行.你不关心飞行员如何驾驶飞机或者哪个航空公司可用......你真的无法预测.你想要的只是获得通风口并告诉他们带你到目的地.

但如果你这样做,你对机场当局的命令将被嘲笑!他们需要你提供一个命令对象,这是你的票.尽管你不关心哪家航空公司或哪种飞机类型,但是当你准备好飞行时,你需要提供一个票务命令对象.调用者,机场官员需要检查你的命令(票证),以便他们可以验证它,如果它是假的则撤消它,如果他们犯了错误就重做它(你不必经过整个预订过程) .

简而言之,他们希望在决定是否调用或执行您的命令之前完全控制您的命令(票证),从而让航空公司(接收方)执行(将您带到飞机上并带您到达目的地).

请注意,您的命令(您的机票)已经有接收方(航空公司)的信息,没有这些信息,机场官员甚至不会首先开始处理您的机票.

机场当局甚至可能有一堆他们正在处理的门票.他们可能会选择延迟我的机票,让跟在我后面的人通过(在我之前调用另一张人的机票)

这是代码:

 [TestClass]
    public class Client
    {
        [TestMethod]
        public void MyFlight_UsingCommandPattern()
        {
            var canadianAirline = new Airline();

            AirlineTicket_Command myTicket = new MyAirLineTicket(canadianAirline);

            var airportOfficials = new AirportOfficials_Invoker(myTicket);
            airportOfficials.ProcessPasengerTicket_And_AllowPassengerToFly_Execute();

            //assert not implemented
        }
    }

    public class AirportOfficials_Invoker
    {
        private AirlineTicket_Command PassengerTicket { set; get; }

        public AirportOfficials_Invoker(AirlineTicket_Command passengerTicket)
        {
            throw new NotImplementedException();
        }

        public void ProcessPasengerTicket_And_AllowPassengerToFly_Execute()
        {
            PassengerTicket.Execute();
        }
    }

    public abstract class AirlineTicket_Command
    {
        protected Airline Airline { set; get; }

        protected AirlineTicket_Command(Airline airline)
        {
            Airline = airline;
        }

        public abstract void Execute();
    }

    public class MyAirLineTicket : AirlineTicket_Command
    {
        public MyAirLineTicket(Airline airline)
            : base(airline)
        {
        }

        public override void Execute()
        {
            Airline.FlyPassenger_Action();
        }
    }

    public class Airline
    {
        public void FlyPassenger_Action()
        {
//this will contain all those stuffs of getting on the plane and flying you to your destination
        }
    }
Run Code Online (Sandbox Code Playgroud)