Command Examples:






To showcase the Command pattern, we'll be creating a basic implementation of a text editor. This includes the ability to add content(type it on the page), backspace to remove content, and the ability to undo and redo our actions.
We'll start out with a Document class that will contain the text data and actions to add and remove content:
class TextDocument
{
   protected content: string;
   constructor()
   {
       this.content = "";
   }
   public printDocument()
   {
       console.log(this.content);
   }
   public addContent(content: string)
   {
       this.content += content;
   }
   public length(): number
   {
       return this.content.length;
   }
   public charAt(index: number): string
   {
       return this.content[index];
   }
   public removeContent(numChars: number)
   {
       if(numChars < 0) return;
       if(numChars > this.content.length - 1)
       {
           this.content = "";
           return;
       }
       this.content = this.content.substring(0, this.content.length - numChars);
   }
}
Next, we'll want to create an interface for our commands. We'll want to have the usual execute method, in addition to undo and redo methods:
interface IUndoableCommand
{
   execute(): void;
   undo(): void;
   redo(): void;
}
class AddContentCommand implements IUndoableCommand
{
   document: TextDocument;
   content: string;
   
   constructor(document: TextDocument, content: string)
   {
       this.document = document;
       this.content = content;
   }
   execute() {
       this.document.addContent(this.content);
   }
   undo() {
       this.document.removeContent(this.content.length);
   }
   redo() {
       this.execute();
   }
   
}
class BackspaceCommand implements IUndoableCommand
{
   document: TextDocument;
   removedChar: string;
   
   constructor(document: TextDocument)
   {
       this.document = document;
       this.removedChar = null;
   }
   execute()
   {
       this.removedChar = this.document.charAt(this.document.length() - 1);
       this.document.removeContent(1);
   }
   undo() 
   {
       this.document.addContent(this.removedChar);
   }
   redo()
   {
       this.execute();
   }
   
}
Lastly, we'll want to create a Document writer that will hold onto a list of our actions in order to undo and redo inputs:
class DocumentWriter
{
   undoStack: Array<IUndoableCommand>;
   redoStack: Array<IUndoableCommand>;
   document: TextDocument;
   constructor(document: TextDocument)
   {
       this.document = document;
       this.undoStack = new Array<IUndoableCommand>();
       this.redoStack = new Array<IUndoableCommand>();
   }
   public write(content: string)
   {
       const command = new AddContentCommand(this.document, content);
       this.undoStack.push(command);
       this.redoStack = new Array<IUndoableCommand>();
       command.execute();
   }
   public backspace()
   {
       if(this.document.length() == 0) return;
       const command = new BackspaceCommand(this.document);
       this.undoStack.push(command);
       this.redoStack = new Array<IUndoableCommand>();
       command.execute();
   }
   public undo()
   {
       if(this.undoStack.length > 0)
       {
           const command = this.undoStack.pop();
           this.redoStack.push(command);
           command.undo();
           
       }
   }
   public redo()
   {
       if(this.redoStack.length > 0)
       {
           const command = this.redoStack.pop();
           this.undoStack.push(command);
           command.redo();
       }
   }
}
class CommandSolution
{
   public execute()
   {
       let doc = new TextDocument();
       let writer = new DocumentWriter(doc);
       // Write to the document:
       writer.write("Hello world!");
       doc.printDocument(); // Hello world!
       writer.backspace();
       doc.printDocument(); // Hello world
       writer.undo();
       doc.printDocument(); // Hello world!
       writer.redo();
       doc.printDocument(); // Hello world
       writer.write(" Goodbye!"); 
       doc.printDocument(); // Hello world Goodbye!
       writer.undo();
       doc.printDocument(); // Hello world
       writer.undo();
       doc.printDocument(); // Hello world!
   }
}
const solution = new CommandSolution();
solution.execute();
Find any bugs in the code? let us know!