Design Pattern -- 17. Behavioral. Command. Pattern (CSharp Sample)

Source: Internet
Author: User
Intent
  • Encapsulate a request as an object, thereby leize you parameterize clients with different requests, queue or log requests, and support undoable operations.
  • Promote "invocation of a method on an object" to full object status
  • An object-oriented callback
Problem

Need to issue requests to objects without knowing anything about the operation being requested or the processing er of the request.

Discussion

Command decouples the object that invokes the operation from the one that knows how to perform it. to achieve this separation, the designer creates an abstract base class that maps a extends Er (an object) with an action (a pointer to a member function ). the base class containsexecute()Method that simply callthe action on the specified er.

All clients of Command objects treat each object as a "black box" by simply invoking the object's virtualexecute()Method whenever the client requires the object's "service ".

A Command class holds some subset of the following: an object, a method to be applied to the object, and the arguments to be passed when the method is applied. the Command's "execute" method then causes the pieces to come together.

Sequences of Command objects can be assembled into composite (or macro) commands.

Structure

The client that creates a command is not the same client that executes it. this separation provides flexibility in the timing and sequencing of commands. materializing commands as objects means they can be passed, staged, shared, loaded in a table, and otherwise instrumented or manipulated like any other object.

Command objects can be thought of as "tokens" that are created by one client that knows what need to be done, and passed to another client that has the resources for doing it.

Example

The Command pattern allows requests to be encapsulated as objects, thereby allowing clients to be parameterized with different requests. the "check" at a diner is an example of a Command pattern. the waiter or waitress takes an order or command from a customer and encapsulates that order by writing it on the check. the order is then queued for a short order cook. note that the pad of "checks" used by each waiter is not dependent on the menu, and therefore they can support commands to cook has different items.

Check list
  1. Define a Command interface with a method signature likeexecute().
  2. Create one or more derived classes that encapsulate some subset of the following: a "login er" object, the method to invoke, the arguments to pass.
  3. Instantiate a Command object for each deferred execution request.
  4. Pass the Command object from the creator (aka sender) to the invoker (aka handler ER ).
  5. The invoker decides whenexecute().
Rules of thumb
  • Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Command normally specifies a sender-inform er connection with a subclass.
  • Chain of Responsibility can use Command to represent requests as objects.
  • Command and Memento act as magic tokens to be passed around and invoked at a later time. in Command, the token represents a request; in Memento, it represents the internal state of an object at a particle time. polymorphism is important to Command, but not to Memento because its interface is so narrow that a memento can only be passed as a value.
  • Command can use Memento to maintain the state required for an undo operation.
  • MacroCommands can be implemented with Composite.
  • A Command that must be copied before being placed on a history list acts as a Prototype.
  • Two important aspects of the Command pattern: interface separation (the invoker is isolated from the specified ER ), time separation (stores a ready-to-go processing request that's to be stated later ).
Command in Delphi

This session consists of the development of a small application to read and pretty-print XML and CSV files. along the way, we explain and demonstrate the use of the following patterns: State, Interpreter, Visitor, Strategy, Command, Memento, and Facade.

Encapsulate a request as an object, thereby letting you parameterise clients with different requests, queue or log requests, and support undoable operations.

The Command pattern is implemented in Delphi (since Delphi 4) in actions. we won't use them, as I want to concentrate on the pattern. actions are complex beasts, and this complexity might detract attention away from the points I want to make. there may well also be occasions where actions are not appropriate, so you may like to know how to roll your own Command structure.

We're re going to use Command for the last of the above options, to implement an undo/redo list, and also to shield our user interface code from having to know anything about operations or the operations on them. after we 've discussed how to do that, you should be able to see how you cocould add logging, queues, and so on.

In its simplest form, the Command pattern consists of an abstract base class withExecuteMethod. concrete subclasses are declared for each possible action, and the method implemented in each so as to carry out that action. usually this requires a call to another class's interface. for instance, in our example, one command wocould be to open a file. after prompting for a file name, the open command will call a document object's OpenFile method. this second object is called the specified er. the object that asks the command to carry out a request is called the invoker. this is often something like a menu item or a button. we are going to do something a little different, though, as we'll see later.

The declaration of our command class (in DocumentCommands. pas) is:

  1: TDocumentCommand = class(TObject)
  2: private
  3:   FDocument : TDocument;
  4: protected
  5:   procedure DoExecute; virtual; abstract;
  6:   procedure DoRollback; virtual;
  7:  
  8:   // Used Self Encapsulate Field refactoring here. Now descendant commands
  9:   // can access the document, even if they are declared in other units
 10:   property Document : TDocument read FDocument write FDocument;
 11: public
 12:   constructor Create(ADocument : TDocument);
 13:  
 14:   procedure Execute;
 15:   procedure Rollback; // Reverse effect of Execute
 16: end;
 17: 
 18: The implementation is: 
 19: constructor TDocumentCommand.Create(ADocument : TDocument);
 20: begin
 21:   inherited Create;
 22:   FDocument := ADocument;
 23: end;
 24: 
 25: procedure TDocumentCommand.DoRollback;
 26: begin
 27: end;
 28: 
 29: procedure TDocumentCommand.Execute;
 30: begin
 31:   if Assigned(FDocument) then begin
 32:     DoExecute;
 33:   end;
 34: end;
 35: 
 36: procedure TDocumentCommand.Rollback;
 37: begin
 38:   if Assigned(FDocument) then begin
 39:     DoRollback;
 40:   end;
 41: end;

Let’s examine what’s going on here. We have two public methods, one to perform a command, and another to reverse it. We need this last one because we want to support undo. Note that both these methods check to see if the document is available before calling another, protected, method. This is a very simple example of the Template pattern. We don’t want programmers who are implementing new commands to have to remember to do that, so we will do it for them here, and they need to override the DoExecute and DoRollback methods instead.

The DoRollback method implementation is empty because a command might not be able to be undone (we are only going to support this on pretty printing and search-and-replace), so we don’t want to force subclasses to implement it by making the method abstract. However, we do want the command to be implemented, so the DoExecute method is abstract to force it to be overridden.

The constructor gets the document passed as a parameter, and that will be used as the receiver in our example. For instance, the Open command is implemented as follows:

  1: procedure TOpenCommand.DoExecute;
  2:   var
  3:     FileName : string;
  4: begin
  5:   if PromptForFileName(FileName,'XML files (*.xml)|*.xml|CSV files (*.csv)|*.csv') then begin
  6:     FDocument.OpenFile(FileName);
  7:   end;
  8: end;
  9: 

Here we call the Delphi function PromptForFileName, and if the user doesn’t cancel the operation, we call the document’s OpenFile method to load the text. For other commands, it gets a little more complex, and we start to see the advantages of separating the command logic out from the object that invokes it.

Other advantages are that it is easy to add new commands, because existing classes don’t need to change. This makes it a lower risk modification to your code. You can also use the Composite pattern to make larger macro commands out of several other commands.

Although our command implementations all make use of a receiver to ultimately carry out the operation, that’s not always necessary. The GoF example is that of a command to launch another application. The command may well have enough information to do that itself (by calling ShellExecute, say), without having to delegate the task to another object. It may also be necessary sometimes for the command to find its receiver dynamically. If our example application used MDI, then we might need to go and find the current document, for instance.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.