java 使用命令设计模式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2015549/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 18:56:00  来源:igfitidea点击:

Using Command Design pattern

javaoopdesign-patternscommand-pattern

提问by RKCY

Can any one explain with simple example of Command Pattern. I refer in internet but i got confused.

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

回答by Droo

public interface Command {
   public void execute();
}

For the most part, commands are immutable and contain instructions that encapsulate a single action that is executed on demand. You might also have a RuntimeCommand that accepts instructions upon execution, but this delves more into the Strategy or Decorator Patterns depending on the implementations.

在大多数情况下,命令是不可变的,并且包含封装按需执行的单个操作的指令。您可能还有一个 RuntimeCommand 在执行时接受指令,但这更多地深入研究了策略或装饰器模式,具体取决于实现。

In my own opinion, I think it's very important to heed the immutable context of a command otherwise the command becomes a suggestion. For instance:

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

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

I personally don't really like commands. In my own experience, they only work well for framework callbacks.

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

If it helps, think of a command in a metaphorical sense; a trained soldier is given a command by his/her commanding officer, and on demand the soldier executes this command.

如果有帮助,请从隐喻的意义上想一个命令;受过训练的士兵由他/她的指挥官下达命令,并根据要求执行该命令。

回答by Ravindra babu

You can think of Command pattern workflow as follows.

您可以将命令模式工作流程视为如下。

Clientcalls Invoker=> Invokercalls ConcreteCommand=> ConcreteCommandcalls Receivermethod, which implements abstract Commandmethod.

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

UML Diagramfrom dofactoryarticle:

来自dofactory文章的UML 图

enter image description here

在此处输入图片说明

Key features:

主要特点:

  1. Commanddeclares an interface for all commands, providing a simple execute() method which asks the Receiver of the command to carry out an operation.

  2. The Receiverhas the knowledge of what to do to carry out the request.

  3. The Invokerholds a command and can get the Commandto execute a request by calling the execute method.

  4. The Clientcreates ConcreteCommandsand sets a Receiverfor the command.

  5. The ConcreteCommanddefines a binding between the action and the receiver.

  6. When the Invokercalls execute the ConcreteCommandwill run one or more actions on the Receiver.

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

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

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

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

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

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

Code snippet:

代码片段:

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

output:

输出:

Switch on from TV
Switch on from DVDPlayer

Explanation:

解释:

In this example,

在这个例子中,

  1. Commandinterface defines execute()method.
  2. OnCommandis ConcreteCommand, which implements execute()method.
  3. Receiveris an interface and implementers have to provide implementation for the methods.
  4. TVand DVDPlayerare two types of Receivers, which are passed to ConcreteCommand like OnCommand.
  5. Invokercontains Command. It's the key to de-couple Sender from Receiver.
  6. Invokerreceives OnCommand-> which calls Receiver(TV) to execute this command.
  1. 命令接口定义execute()方法。
  2. OnCommandConcreteCommand,它实现了execute()方法。
  3. Receiver是一个接口,实现者必须为这些方法提供实现。
  4. TVDVDPlayer是两种类型的Receivers,它们像 OnCommand 一样传递给 ConcreteCommand。
  5. Invoker包含Command。这是将 Sender 与Receiver解耦的关键。
  6. Invoker接收OnCommand-> 调用Receiver(TV) 来执行这个命令。

By using Invoker, you can switch on TV and DVDPlayer. If you extend this program, you switch off both TV and DVDPlayer too.

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

You can use Commandpattern to

您可以使用命令模式来

  1. Decouple the sender & receiver of command

  2. Implement callback mechanism

  3. Implement undo and redo functionality

  4. Maintain a history of commands

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

  2. 实现回调机制

  3. 实现撤销和重做功能

  4. 维护命令的历史记录

Have a look at this dzoneand journaldevand Wikipediaarticles.

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

Source code as Wikipedia page is simple, cleaner and self explanatory.

维基百科页面的源代码简单、清晰且不言自明。

You can implement Undoand Redoif you follow the steps as quoted in this article

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

回答by Samuel

Here is another example you can use to understand how command pattern works, using real life scenarios: You cannot travel from one place to another by airplane without using the command pattern!

下面是另一个示例,您可以使用现实生活场景来了解命令模式的工作原理:如果不使用命令模式,就无法乘飞机从一个地方旅行到另一个地方!

If you are a frequent traveler, all you care about as a client is to travel from where you are to another . you don't care about how the pilot will fly the plane or which airline will be available .. you cant really predict that. all you want is to get the the air port and tell them to take you to your destination.

如果您经常出差,作为客户,您所关心的只是从您所在的地方到另一个地方。你不关心飞行员将如何驾驶飞机或哪家航空公司可用......你无法真正预测这一点。您想要的只是到达机场并告诉他们带您到目的地。

But if you do that, your command to the airport authorities will be laughed at! they need you to supply a command object, which is your ticket. as much as you don't care about which airline or which plane type, when you are ready to fly, you need to supply a ticket command object. The invoker, which is the airport officials needs to check your command (ticket) so that they can validate it, undo it if it is fake, redo it if they made a mistake (without you having to go through the booking process all over).

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

In short , they want to have complete control of your command (ticket) before deciding whether or not to invoke or execute your command, which lets the airline (the receiver ) execute ( put you on a plane and take you to your destination) .

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

Mind you, your command (your ticket) already has the information of the receiver (airline) without which the airport officials wont even start to process your ticket in the first place.

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

The airport authorities could even have a bunch of tickets they are working on. they may choose to delay my ticket and let someone that came after me go through (invoke another persons ticket before mine)

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

Here is the code :

这是代码:

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

回答by rsinha

My requirement is to perform a sequence of tasks (which can be re-used in several Usecases) each with its own exception flow. Found Command pattern's implementation logical here.

我的要求是执行一系列任务(可以在多个用例中重复使用),每个任务都有自己的异常流。找到命令模式的实现逻辑here。

I am trying to make it like each action executed by the command (whether normal/alternate flow) can be an exception handler too. However, If the command is registered with another handler then this should be used. Any suggestions for improvement/correction are welcome.

我试图让它像命令执行的每个操作(无论是正常/备用流)也可以是异常处理程序。但是,如果该命令已注册到另一个处理程序,则应该使用它。欢迎任何改进/更正建议。

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

    }
}

回答by Mangu Singh Rajpurohit

Command Design Patterns decouples invoker of service and provider of service. In general scenario, say for eg., If Object Awants service of Object B, it'll directly invoke B.requiredService(). Thus, A is aware about B. In Command pattern, this coupling is removed. Here, there's an intermediate object known as Command, which comes into picture. Thus, Adeals with Commandobject and command object deals with actual object B. This approach has several applications such as designing applications, which are :-

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

  • Accepts commands as requests.
  • Undoing requests.
  • Requests requests.
  • Creating macros.
  • Creating Task Executors and Task Managers.
  • 接受命令作为请求。
  • 撤消请求。
  • 请求请求。
  • 创建宏。
  • 创建任务执行器和任务管理器。

For more information regarding, Command Design Pattern, I'll recommend https://en.wikipedia.org/wiki/Command_pattern. For all other design patterns, refer to https://www.u-cursos.cl/usuario/.../mi_blog/r/head_first_design_patterns.pdf

有关命令设计模式的更多信息,我会推荐https://en.wikipedia.org/wiki/Command_pattern。对于所有其他设计模式,请参阅https://www.u-cursos.cl/usuario/.../mi_blog/r/head_first_design_patterns.pdf

回答by vishal

I would try to give you another rough analogy here.

我会在这里尝试给你另一个粗略的类比。

Suppose that one day God calls on you and tells you that the world's in danger and He needs your help to save it. Further helping you , He tells you that He has sent some superheroes on earth.

假设有一天上帝呼唤你,告诉你世界处于危险之中,他需要你的帮助来拯救它。进一步帮助你,他告诉你他在地球上派了一些超级英雄。

Since He doesn't know oops and hence He doesn't call them superheroes (doesn't provide you any interface or abstract class over them) but just tell you their names for ex - batman, superman, iron man and the powers they have.

因为他不知道哎呀,因此他不称他们为超级英雄(不为您提供任何接口或抽象类),而只是告诉您他们的前蝙蝠侠,超人,钢铁侠的名字以及他们拥有的权力.

He also says that in future He might send more such guys in future.

他还说,将来他可能会派更多这样的人。

Now He assigns you special responsibility -> control them and for that provides you with seven hands. He doesn't fixes the task of each hand Himself but leaves it on you.

现在他分配给你特殊的责任 ->控制他们,为此你提供了七只手。他不会亲自确定每一只手的任务,而是把它留给你。

You want flexibility in assigning any hand control of any superhero's power and don't want to repeatedly change things through multiple conditions.

您希望灵活地分配对任何超级英雄的力量的任何手动控制,并且不想在多个条件下重复改变事物。

You are in a fix. What do you do now?

你正在修复中。你现在做什么?

Enter Command Pattern.

输入命令模式。

Create an interface Command and has only one method execute() in it. Encapsulate every power of each superhero and make that implement Command for ex - IronManCreatesSuitCommand

创建一个接口 Command,其中只有一个方法 execute()。封装每个超级英雄的每一个力量,并为 ex-IronManCreatesSuitCommand 实现命令

Now you can assign any hand to any command at any time giving you lot more flexibility because now none of your hands cares about the specific task it has to do. You just assign it any command to it. It calls execute on it and the command takes care of everything else.

现在您可以随时将任何手分配给任何命令,从而为您提供更大的灵活性,因为现在您的任何手都不关心它必须执行的特定任务。您只需为其分配任何命令即可。它调用 execute 并且命令负责处理其他所有事情。

Now even when God sends any other superhero with different powers, you know what to do.

现在,即使上帝派任何其他具有不同力量的超级英雄,你也知道该怎么做。