A segment of the client community needs a simplified interface to the overall functionality of a complex subsystem.
Facade discusses encapsulating a complex subsystem within a single interface object. This reduces the learning curve necessary to successfully leverage the subsystem. It also promotes decoupling the subsystem from its potentially many clients. On the other hand, if the Facade is the only access point for the subsystem, it will limit the features and flexibility that “power users” may need.
The Facade object should be a fairly simple advocate or facilitator. It should not become an all-knowing oracle or “god” object.
Facade takes a “riddle wrapped in an enigma shrouded in mystery”, and interjects a wrapper that tames the amorphous and inscrutable mass of software.
SubsystemOne
and SubsystemThree
do not interact with the internal components of SubsystemTwo
. They use the SubsystemTwoWrapper
“facade” (i.e. the higher level abstraction).
The Facade defines a unified, higher level interface to a subsystem that makes it easier to use. Consumers encounter a Facade when ordering from a catalog. The consumer calls one number and speaks with a customer service representative. The customer service representative acts as a Facade, providing an interface to the order fulfillment department, the billing department, and the shipping department.
Question: So the way to tell the difference between the Adapter pattern and the Facade pattern is that the Adapter wraps one class and the Facade may represent many classes?
Answer: No! Remember, the Adapter pattern changes the interface of one or more classes into one interface that a client is expecting. While most textbook examples show the adapter adapting one class, you may need to adapt many classes to provide the interface a client is coded to. Likewise, a Facade may provide a simplified interface to a single class with a very complex interface. The difference between the two is not in terms of how many classes they “wrap”, it is in their intent.
Delphi Sample
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.
Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
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 is defined in CommandFacade.pas as follows:
1: TCommandFacade = class(TObject)2: private3: FCommandList : TObjectList;4: FCurrCommand : Integer;5: // Possibly this should be registered, rather than created here
6: FDocument : TDocument;7: FMemo : TMemo;8:9: procedure ClearOldCommands;
10: procedure PerformCommand(CommandClass : TDocumentCommandClass; ClearCommandList : Boolean);
11: procedure UpdateMemo;
12: protected13: public14: constructor Create;
15: destructor Destroy; override;
16:17: procedure OpenDocument;
18: procedure CloseDocument;
19: procedure Undo;
20: procedure Redo;
21: procedure SearchAndReplace;
22: procedure PrettyPrint;
23:24: // This allows a memo control to be updated when the document content
25: // changes. This should really be an Observer etc, but the session is
26: // only so long!
27: procedure RegisterMemo(AMemo : TMemo);
28: end;
29:
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.
If we look at the code for the pretty printing command method, we can see how the four main actions are implemented:
1: procedure TCommandFacade.PrettyPrint;
2: begin
3: PerformCommand(TPrettyPrintCommand,False);4: UpdateMemo;5: end;
6:
The PerformCommand
routine does this:
1: procedure TCommandFacade.PerformCommand(CommandClass : TDocumentCommandClass; ClearCommandList : Boolean);
2: var
3: NewCommand : TDocumentCommand;4: begin
5: NewCommand := CommandClass.Create(FDocument);6:7: try8: NewCommand.Execute;9:10: if ClearCommandList then begin11: FCommandList.Clear;12: end else begin13: // If have done an undo and then choose a new command, clear the
14: // old following commands
15: ClearOldCommands;16: FCurrCommand := FCommandList.Add(NewCommand);17: end;
18: except19: // Only add command to the command list if doesn't raise an exception
20: NewCommand.Free;21: end;
22: end;
23:
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.
unify ['ju:nifai]
· vt. 统一;使相同,使一致
complicated ['kɔmplikeitid]
· adj. 难懂的,复杂的
curve [kə:v]
· n. 曲线;弯曲;曲线球;曲线图表
· vt. 弯;使弯曲
· vi. 成曲形
· adj. 弯曲的;曲线形的
leverage ['li:vəridʒ, 'le-]
· n. 杠杆作用;杠杆效率;手段,影响力
potentially [pə'tenʃəli]
· adv. 可能地,潜在地
advocate ['ædvəkeit, 'ædvəkət]
· vt. 提倡,主张,拥护
· n. 提倡者;支持者;律师
oracle ['ɔrəkl, 'ɔ:-]
· n. 神谕;神谕处;预言;圣人
riddle ['ridl]
· vt. 解谜;给...出谜;充满于
· n. 谜语;粗筛;谜一般的人、东西、事情等
· vi. 出谜
enigma [i'niɡmə]
· n. 谜,不可思议的东西
shroud [ʃraud]
· n. 寿衣;覆盖物;船的横桅索;[电] 护罩
· vt. 覆盖;包以尸衣
interject [,intə'dʒekt]
· vt. 突然插入;插嘴
tame [teim]
· adj. 驯服的;平淡的;乏味的;顺从的
· vt. 驯养;使变得平淡;制服
· vi. 变得驯服
amorphous [ə'mɔ:fəs]
· adj. 无定形的;无组织的;[物] 非晶形的
inscrutable [in'skru:təbl]
· adj. 神秘的;不可理解的;不能预测的;不可思议的