Normally, to implement the Facade pattern, you need to define a facade class, which acts as the sole interface of some subsystem to other classes. Usually this is because the subsystem is quite complex, often as a result of refactoring and applying design patterns. These practices often result in more, smaller classes, which can be difficult for clients to use. Often they are tightly coupled as well. Using a facade hides that.
You can also use a facade to shift dependencies between elements of the subsystem and the clients that use them to being between clients and the facade, reducing the overall coupling of the application. Changes can be made to the subsystem without affecting the clients.
In either case, subsystem objects should not keep a reference to the facade, but should only perform tasks assigned to them.
Our facade object will keep a list of the commands that have been executed in the FCommandList field, and keep track of the last executed one in FCurrCommand. We will also store the document object for the application here, so that we can pass it to the commands as necessary. We also have a list of methods, each representing one of the available commands. Notice that we have two extra – undo and redo – that we will examine in more detail in a minute.
The last thing we have is a reference to the memo control that will display the document. We attach this by using the RegisterMemo method. Ideally, we would implement the Observer or Mediator pattern to track changes, but this paper is long enough already.
We create a new command object, with its concrete class being determined by the type of command to execute. Opening a file or closing a file will clear the undo/redo list, pretty printing or doing a search-and-replace will add the command to the end of the list. If we have rolled back through the list, all the commands we have undone will be removed from the list before adding the new one. After performing the command action, the memo is updated to show the new document text (which might be blank if we closed the file).
If you look at the source code that implements undo and redo, you will find that they move through the undo/redo list executing the relevant command. ).
We have a very simple implementation here, and you should refer to the GoF book for ways in which an undo/redo list might be modified under other circumstances. It's an example that stretches over several patterns, as we have discovered, but there are still others that can apply, like Flyweight, for instance.
The one last pattern that we will apply is Singleton. We will make sure our facade object can only have one instance created at a time. We'll use the simple method of counting the instances, but you will find there are more complex ways to do this. I've always found them to be overkill, but your mileage may vary. Our global Commands variable is created and destroyed in the initialization and finalization sections of the CommandFacade.pas unit.
To see how much difference using Facade makes, you should look at the user interface code in MainForm.pas, where you will see that the code for each menu item event handler has one line of code. What would have been quite complex, managing documents, command lists, parsers, interpreters, and so on is now completely hidden from the UI. If we wanted to change the interface it would be a doddle. Adding new commands is also pretty easy.
More info, diagrams and examples of the Facade design pattern you can find on our new partner resource Refactoring.Guru.