使用Command Design模式

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

public interface Command { public void execute(); } 

在大多数情况下,命令是不可变的,并包含封装按需执行的单个操作的指令。 您可能还有一个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(); } }); } } 

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

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

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

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

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

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

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

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

这是代码:

  [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 } } 

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

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

来自dofactory文章的UML图

在此处输入图像描述

主要特征:

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

  2. 接收方知道如何执行请求。

  3. Invoker拥有一个命令,可以通过调用execute方法让Command执行请求。

  4. 客户端创建ConcreteCommands并为命令设置Receiver

  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(); } } 

输出:

 Switch on from TV Switch on from DVDPlayer 

说明:

在这个例子中,

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

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

您可以使用命令模式

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

  2. 实现回调机制

  3. 实现撤消和重做function

  4. 保持命令的历史

看看这个dzone和journaldev以及维基百科的文章。

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

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

我的要求是执行一系列任务(可以在几个Usecases中重用),每个任务都有自己的exception流程。 在这里找到Command模式的实现逻辑。

我试图让它像命令执行的每个动作(无论正常/备用流程)也可以是exception处理程序。 但是,如果该命令是使用其他处理程序注册的,则应使用此命令。 欢迎任何改进/纠正的建议。

 public interface Command { Result run() throws Exception; Command onException(ExceptionHandler handler); } public class Result { } public interface ExceptionHandler { void handleException(Exception e); } public interface Action { Result execute() throws Exception; } public class BasicCommand implements Command { private Action action; private ExceptionHandler handler; public BasicCommand(Action action) { if (action == null) { throw new IllegalArgumentException("Action must not be null."); } this.action = action; this.handler = (ExceptionHandler) this.action; } @Override public Command onException(ExceptionHandler handler) { if (handler != null) { this.handler = handler; } return this; } public Result run() throws Exception { Result result = null; try { result = action.execute(); } catch (Exception e) { handler.handleException(e); } return result; } 

}

 public class BasicAction implements Action, ExceptionHandler { private Object[] params; public BasicAction(Object... params) { this.params = params; } @Override public Result execute() throws Exception { // TODO Auto-generated method stub return null; } @Override public void handleException(Exception e) { // TODO exception translation: prepare unchecked application. exception and throw.. } } public class Main { public static void main(String[] args) throws Exception { int param1 = 10; String param2 = "hello"; // command will use the action itself as an exception handler Result result = new BasicCommand(new BasicAction(param1, param2)).run(); ExceptionHandler myHandler = new ExceptionHandler(){ @Override public void handleException(Exception e) { System.out.println("handled by external handler"); } }; // command with an exception handler passed from outside. Result result2 = new BasicCommand(new BasicAction(param1, param2)).onException(myHandler).run(); } } 

命令设计模式将服务调用者和服务提供者分离。 在一般场景中,例如,如果Object A想要Object B服务,它将直接调用B.requiredService() 。 因此,A知道B.在命令模式中,删除了这种耦合。 在这里,有一个称为Command的中间对象,它进入了画面。 因此, A处理Command对象和命令对象处理实际对象B 这种方法有几个应用程序,如设计应用程序,它们是:

  • 接受命令作为请求。
  • 撤消请求。
  • 请求请求。
  • 创建宏。
  • 创建任务执行程序和任务管理器。

有关Command Design Pattern的更多信息,我建议您使用https://en.wikipedia.org/wiki/Command_pattern 。 有关所有其他设计模式,请参阅https://www.u-cursos.cl/usuario/…/mi_blog/r/head_first_design_patterns.pdf