Implement a Command Pattern Using C#

Implement a Command Pattern Using C#

With Visual Studio.NET IDE, one can easily add user interface objects such as menus and toolbar buttons to a form and let the IDE generate event handlers skeleton code in the form’s design window to handle the events triggered by pressing toolbar buttons or selecting menus. Although this automatic code generation makes the user interface design and coding very easy, for a large, complex Windows application, a great amount of event handling code is dumped into the form class and makes the form class code increasingly bulky and difficult to maintain. From the viewpoint of object-oriented design, this is also not a very good design and the code cannot be re-used.

Buttons or menu items usually carry out a request in response to user input, which then causes an action to be invoked. The command design pattern lets these user interface objects make requests of unspecified application objects by turning the request itself into an object. This object can be stored and passed around like other objects. This separation of user interface objects from the receivers of the requests makes the code easy to maintain and promotes code re-use.

This article gives an example of an implementation of the Command pattern using C# in a Windows application.

The Application

The application is just for demo purposes and therefore it is not a real-world one. It is a simple text editor with Open File and Save File menu items in the File menu; and Copy, Cut, and Paste menu items in the Edit menu. It also has Open File, Save File, Copy, and Paste tool strip buttons. Each of these user interface objects has a reference to a command object that is derived from an abstract base command class. When a click event is triggered, the user interface object invokes the Execute method of the concrete command object. The concrete command class has a reference to an editor object and delegate the task to the editor object. A concrete command object is created by a command factory that provides factory methods for each concrete command class.

The Text Editor Class

The TextEditor class contains a Windows textbox and methods to open and save a text file and copy, cut, and and paste text in the text box. The TextEditor also handles the shortcut keys Ctrl+X for cut, Ctrl+V for paste, and Ctrl+Z for undo. When it receives a Ctrl+X or Ctrl+V shortcut key, it creates a Cut or Paste command object and pushes it to a command stack owned by an undo command object for a possible undo operation later on. Therefore, the TextEditor also has a reference to the command factory and undo command object. I’ll discuss the command factory and undo command later.

public class TextEditor
{
   private CmdFactory _factory;
   private UndoCmd _undoCmd;
   private TextBox _textBox;
   private OpenFileDialog _openFileDlg;
   private string _filePath;

   public TextEditor(TextBox textBox)
   {
      _textBox = textBox;
      _undoCmd = null;
      _openFileDlg = new OpenFileDialog();
      this._textBox.KeyDown +=
         new System.Windows.Forms.
         KeyEventHandler(this.TextBoxKeyDown);
   }

   // Properties, methods, and KeyDown event handler below.

}

The Command Factory Class

The CmdFactory command factory class has a reference to TextEditor and provides factory methods to produce command objects.

public class CmdFactory
{
   private TextEditor _editor;

   public CmdFactory(TextEditor editor)
   {
      _editor = editor;
      _editor.CmdFactory = this;
   }

   public OpenFileCmd OpenFileCmd()
   {
      return new OpenFileCmd(_editor, this);


   }

   public SaveFileCmd SaveFileCmd()
   {
      return new SaveFileCmd(_editor, this);
   }

   public UndoCmd UndoCmd(CmdMenuItem undoMenuItem)
   {
      return new UndoCmd(_editor, this, undoMenuItem);
   }

   public CopyCmd CopyCmd()
   {
      return new CopyCmd(_editor, this);
   }

   public CutCmd CutCmd()
   {
      return new CutCmd(_editor, this);
   }

   public PasteCmd PasteCmd()
   {
      return new PasteCmd(_editor, this);
   }
}

The Base Class of the Command Classes

The BaseCmd class is the base class of all other command classes. It has references to TextEditor and CmdFactory objects and an abstract method, Execute().

abstract public class BaseCmd
{
   protected TextEditor _editor;
   protected CmdFactory _factory;
   abstract public void Execute();

   public BaseCmd(TextEditor editor, CmdFactory factory)
   {
      _editor = editor;
      _factory = factory;
   }
}

The Concrete Command Classes That Do Not Support Undo

Generally, concrete command classes override the Execute() abstract method of the base class and delegate the operation to TextEditor. Some concrete commands do not support undo operation; for example, open/save file commands, and the copy command. These command classes are directly derived from the BaseCmd class.

public class OpenFileCmd : BaseCmd
{
   public OpenFileCmd(TextEditor editor, CmdFactory factory)
      : base(editor, factory)
   {
   }

   // Delegate Execution operation to OpenFile operation
   // of TextEditor.
   public override void Execute()
   {
      _editor.OpenFile();
   }
}

public class SaveFileCmd : BaseCmd
{
   public SaveFileCmd(TextEditor editor, CmdFactory factory)
      : base(editor, factory)
   {
   }

   public override void Execute()
   {
      _editor.SaveFile();
   }
}

public class CopyCmd : BaseCmd
{
   public CopyCmd(TextEditor editor, CmdFactory factory)
      : base(editor, factory)
   {
   }

   public override void Execute()
   {
      _editor.Copy();
   }
}

Concrete Command Classes That Support Undo Operation

The cut and paste command supports the undo operation. They are derived from the UndoableCmd class that is an abstract class itself and is in turn derived from the BaseCmd class. UndoableCmd has an abstract property, Name, and an abstract method, Undo().

abstract public class UndoableCmd : BaseCmd
{
   public UndoableCmd(TextEditor editor, CmdFactory factory)
      : base(editor, factory)
   {
   }

   abstract public string Name { get; }
   abstract public void Undo();
}

A concrete undoable command class is derived from the UndoabldCmd class. It overrides the Execute() abstract method of the BaseCmd class and the Undo() abstract method of the UndoableCmd class. Here, you take the CutCmd class for the cut command as an example.

public class CutCmd : UndoableCmd
{
   private int _selStart;
   private string _selText;

   public CutCmd(TextEditor editor, CmdFactory factory)
      : base(editor, factory)
   {
      _selStart = editor.SelectionStart;
      _selText = editor.SelectedText;
   }

   public override string Name
   {
      get { return "Cut"; }
   }

   public override void Execute()
   {
      CutCmd cmd = _factory.CutCmd();
      _editor.Cut(cmd);
   }

   public override void Undo()
   {
      _editor.UndoCut(_selStart, _selText);
   }
}

Note In the Execute() method of CutCmd, a new instance of CutCmd is created by the command factory. The method calls TextEditor's Cut() method, passing this CutCmd object as the parameter. This is because with each "cut" operation, a CutCmd object needs to be pushed into the command stack of the Undo command object for a possible undo operation. The Cut() method of TextEditor shows how it is accomplished:

// Cut() method of TextEditor
public void Cut(CutCmd cmd)
{
   _textBox.Cut();
   _undoCmd.Push(cmd);
}

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read