// 为了将框架的复杂性隐藏在一个简单接口背后,我们创建了一个外观类。它是在 // 功能性和简洁性之间做出的权衡。 class VideoConverter is method convert(filename, format):Fileis file = new VideoFile(filename) sourceCodec = new CodecFactory.extract(file) if (format == "mp4") destinationCodec = new MPEG4CompressionCodec() else destinationCodec = new OggCompressionCodec() buffer = BitrateReader.read(filename, sourceCodec) result = BitrateReader.convert(buffer, destinationCodec) result = (new AudioMixer()).fix(result) return new File(result)
// 应用程序的类并不依赖于复杂框架中成千上万的类。同样,如果你决定更换框架, // 那只需重写外观类即可。 class Application is method main() is convertor = new VideoConverter() mp4 = convertor.convert("funny-cats-video.ogg", "mp4") mp4.save()
namespaceRefactoringGuru.DesignPatterns.Facade.Conceptual { // The Facade class provides a simple interface to the complex logic of one // or several subsystems. The Facade delegates the client requests to the // appropriate objects within the subsystem. The Facade is also responsible // for managing their lifecycle. All of this shields the client from the // undesired complexity of the subsystem. publicclassFacade { protected Subsystem1 _subsystem1; protected Subsystem2 _subsystem2;
publicFacade(Subsystem1 subsystem1, Subsystem2 subsystem2) { this._subsystem1 = subsystem1; this._subsystem2 = subsystem2; } // The Facade's methods are convenient shortcuts to the sophisticated // functionality of the subsystems. However, clients get only to a // fraction of a subsystem's capabilities. publicstringOperation() { string result = "Facade initializes subsystems:\n"; result += this._subsystem1.operation1(); result += this._subsystem2.operation1(); result += "Facade orders subsystems to perform the action:\n"; result += this._subsystem1.operationN(); result += this._subsystem2.operationZ(); return result; } } // The Subsystem can accept requests either from the facade or client // directly. In any case, to the Subsystem, the Facade is yet another // client, and it's not a part of the Subsystem. publicclassSubsystem1 { publicstringoperation1() { return"Subsystem1: Ready!\n"; }
publicstringoperationN() { return"Subsystem1: Go!\n"; } } // Some facades can work with multiple subsystems at the same time. publicclassSubsystem2 { publicstringoperation1() { return"Subsystem2: Get ready!\n"; }
classClient { // The client code works with complex subsystems through a simple // interface provided by the Facade. When a facade manages the lifecycle // of the subsystem, the client might not even know about the existence // of the subsystem. This approach lets you keep the complexity under // control. publicstaticvoidClientCode(Facade facade) { Console.Write(facade.Operation()); } } classProgram { staticvoidMain(string[] args) { // The client code may have some of the subsystem's objects already // created. In this case, it might be worthwhile to initialize the // Facade with these objects instead of letting the Facade create // new instances. Subsystem1 subsystem1 = new Subsystem1(); Subsystem2 subsystem2 = new Subsystem2(); Facade facade = new Facade(subsystem1, subsystem2); Client.ClientCode(facade); } } }
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
在 C++ 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 使用 C++ 开发的程序中会经常使用外观模式。 它在与复杂程序库和 API 协作时特别有用。
/** * The Subsystem can accept requests either from the facade or client directly. * In any case, to the Subsystem, the Facade is yet another client, and it's not * a part of the Subsystem. */ classSubsystem1 { public: std::string Operation1()const{ return"Subsystem1: Ready!\n"; } // ... std::string OperationN()const{ return"Subsystem1: Go!\n"; } }; /** * Some facades can work with multiple subsystems at the same time. */ classSubsystem2 { public: std::string Operation1()const{ return"Subsystem2: Get ready!\n"; } // ... std::string OperationZ()const{ return"Subsystem2: Fire!\n"; } };
/** * The Facade class provides a simple interface to the complex logic of one or * several subsystems. The Facade delegates the client requests to the * appropriate objects within the subsystem. The Facade is also responsible for * managing their lifecycle. All of this shields the client from the undesired * complexity of the subsystem. */ classFacade { protected: Subsystem1 *subsystem1_; Subsystem2 *subsystem2_; /** * Depending on your application's needs, you can provide the Facade with * existing subsystem objects or force the Facade to create them on its own. */ public: /** * In this case we will delegate the memory ownership to Facade Class */ Facade( Subsystem1 *subsystem1 = nullptr, Subsystem2 *subsystem2 = nullptr) { this->subsystem1_ = subsystem1 ?: new Subsystem1; this->subsystem2_ = subsystem2 ?: new Subsystem2; } ~Facade() { delete subsystem1_; delete subsystem2_; } /** * The Facade's methods are convenient shortcuts to the sophisticated * functionality of the subsystems. However, clients get only to a fraction of * a subsystem's capabilities. */ std::string Operation(){ std::string result = "Facade initializes subsystems:\n"; result += this->subsystem1_->Operation1(); result += this->subsystem2_->Operation1(); result += "Facade orders subsystems to perform the action:\n"; result += this->subsystem1_->OperationN(); result += this->subsystem2_->OperationZ(); return result; } };
/** * The client code works with complex subsystems through a simple interface * provided by the Facade. When a facade manages the lifecycle of the subsystem, * the client might not even know about the existence of the subsystem. This * approach lets you keep the complexity under control. */ voidClientCode(Facade *facade){ // ... std::cout << facade->Operation(); // ... } /** * The client code may have some of the subsystem's objects already created. In * this case, it might be worthwhile to initialize the Facade with these objects * instead of letting the Facade create new instances. */
intmain(){ Subsystem1 *subsystem1 = new Subsystem1; Subsystem2 *subsystem2 = new Subsystem2; Facade *facade = newFacade(subsystem1, subsystem2); ClientCode(facade);
delete facade;
return0; }
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
在 Java 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 使用 Java 开发的程序中经常会使用外观模式。 它在与复杂程序库和 API 协作时特别有用。
/** * The Facade class provides a simple interface to the complex logic of one or * several subsystems. The Facade delegates the client requests to the * appropriate objects within the subsystem. The Facade is also responsible for * managing their lifecycle. All of this shields the client from the undesired * complexity of the subsystem. */ classFacade { protected$subsystem1;
protected$subsystem2;
/** * Depending on your application's needs, you can provide the Facade with * existing subsystem objects or force the Facade to create them on its own. */ publicfunction__construct( Subsystem1 $subsystem1 = null, Subsystem2 $subsystem2 = null ) { $this->subsystem1 = $subsystem1 ?: newSubsystem1(); $this->subsystem2 = $subsystem2 ?: newSubsystem2(); }
/** * The Facade's methods are convenient shortcuts to the sophisticated * functionality of the subsystems. However, clients get only to a fraction * of a subsystem's capabilities. */ publicfunctionoperation(): string { $result = "Facade initializes subsystems:\n"; $result .= $this->subsystem1->operation1(); $result .= $this->subsystem2->operation1(); $result .= "Facade orders subsystems to perform the action:\n"; $result .= $this->subsystem1->operationN(); $result .= $this->subsystem2->operationZ();
return$result; } }
/** * The Subsystem can accept requests either from the facade or client directly. * In any case, to the Subsystem, the Facade is yet another client, and it's not * a part of the Subsystem. */ classSubsystem1 { publicfunctionoperation1(): string { return"Subsystem1: Ready!\n"; }
/** * Some facades can work with multiple subsystems at the same time. */ classSubsystem2 { publicfunctionoperation1(): string { return"Subsystem2: Get ready!\n"; }
/** * The client code works with complex subsystems through a simple interface * provided by the Facade. When a facade manages the lifecycle of the subsystem, * the client might not even know about the existence of the subsystem. This * approach lets you keep the complexity under control. */ functionclientCode(Facade $facade) { // ...
echo$facade->operation();
// ... }
/** * The client code may have some of the subsystem's objects already created. In * this case, it might be worthwhile to initialize the Facade with these objects * instead of letting the Facade create new instances. */ $subsystem1 = newSubsystem1(); $subsystem2 = newSubsystem2(); $facade = newFacade($subsystem1, $subsystem2); clientCode($facade);
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
/** * The Facade provides a single method for downloading videos from YouTube. This * method hides all the complexity of the PHP network layer, YouTube API and the * video conversion library (FFmpeg). */ classYouTubeDownloader { protected$youtube; protected$ffmpeg;
/** * It is handy when the Facade can manage the lifecycle of the subsystem it * uses. */ publicfunction__construct(string$youtubeApiKey) { $this->youtube = newYouTube($youtubeApiKey); $this->ffmpeg = newFFMpeg(); }
/** * The Facade provides a simple method for downloading video and encoding it * to a target format (for the sake of simplicity, the real-world code is * commented-out). */ publicfunctiondownloadVideo(string$url): void { echo"Fetching video metadata from youtube...\n"; // $title = $this->youtube->fetchVideo($url)->getTitle(); echo"Saving video file to a temporary file...\n"; // $this->youtube->saveAs($url, "video.mpg");
// ...more methods and classes... RU: ...дополнительные методы и классы... }
/** * The client code does not depend on any subsystem's classes. Any changes * inside the subsystem's code won't affect the client code. You will only need * to update the Facade. */ functionclientCode(YouTubeDownloader $facade) { // ...
Fetching video metadata from youtube... Saving video file to a temporary file... Processing source video... Normalizing and resizing the video to smaller dimensions... Capturing preview image... Saving video in target formats... Done! 继续
在 Python 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 使用 Python 开发的程序中会经常使用外观模式。 它在与复杂程序库和 API 协作时特别有用。
classFacade: """ The Facade class provides a simple interface to the complex logic of one or several subsystems. The Facade delegates the client requests to the appropriate objects within the subsystem. The Facade is also responsible for managing their lifecycle. All of this shields the client from the undesired complexity of the subsystem. """
def__init__(self, subsystem1: Subsystem1, subsystem2: Subsystem2) -> None: """ Depending on your application's needs, you can provide the Facade with existing subsystem objects or force the Facade to create them on its own. """
self._subsystem1 = subsystem1 or Subsystem1() self._subsystem2 = subsystem2 or Subsystem2()
defoperation(self) -> str: """ The Facade's methods are convenient shortcuts to the sophisticated functionality of the subsystems. However, clients get only to a fraction of a subsystem's capabilities. """
results = [] results.append("Facade initializes subsystems:") results.append(self._subsystem1.operation1()) results.append(self._subsystem2.operation1()) results.append("Facade orders subsystems to perform the action:") results.append(self._subsystem1.operation_n()) results.append(self._subsystem2.operation_z()) return"\n".join(results)
classSubsystem1: """ The Subsystem can accept requests either from the facade or client directly. In any case, to the Subsystem, the Facade is yet another client, and it's not a part of the Subsystem. """
defclient_code(facade: Facade) -> None: """ The client code works with complex subsystems through a simple interface provided by the Facade. When a facade manages the lifecycle of the subsystem, the client might not even know about the existence of the subsystem. This approach lets you keep the complexity under control. """
print(facade.operation(), end="")
if __name__ == "__main__": # The client code may have some of the subsystem's objects already created. # In this case, it might be worthwhile to initialize the Facade with these # objects instead of letting the Facade create new instances. subsystem1 = Subsystem1() subsystem2 = Subsystem2() facade = Facade(subsystem1, subsystem2) client_code(facade)
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
在 Ruby 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 使用 Ruby 开发的程序中会经常使用外观模式。 它在与复杂程序库和 API 协作时特别有用。
# The Facade class provides a simple interface to the complex logic of one or # several subsystems. The Facade delegates the client requests to the # appropriate objects within the subsystem. The Facade is also responsible for # managing their lifecycle. All of this shields the client from the undesired # complexity of the subsystem. classFacade # Depending on your application's needs, you can provide the Facade with # existing subsystem objects or force the Facade to create them on its own. definitialize(subsystem1, subsystem2) @subsystem1 = subsystem1 || Subsystem1.new @subsystem2 = subsystem2 || Subsystem2.new end
# The Facade's methods are convenient shortcuts to the sophisticated # functionality of the subsystems. However, clients get only to a fraction of # a subsystem's capabilities. defoperation results = [] results.append('Facade initializes subsystems:') results.append(@subsystem1.operation1) results.append(@subsystem2.operation1) results.append('Facade orders subsystems to perform the action:') results.append(@subsystem1.operation_n) results.append(@subsystem2.operation_z) results.join("\n") end end
# The Subsystem can accept requests either from the facade or client directly. # In any case, to the Subsystem, the Facade is yet another client, and it's not # a part of the Subsystem. classSubsystem1 # @return [String] defoperation1 'Subsystem1: Ready!' end
# ...
# @return [String] defoperation_n 'Subsystem1: Go!' end end
# Some facades can work with multiple subsystems at the same time. classSubsystem2 # @return [String] defoperation1 'Subsystem2: Get ready!' end
# ...
# @return [String] defoperation_z 'Subsystem2: Fire!' end end
# The client code works with complex subsystems through a simple interface # provided by the Facade. When a facade manages the lifecycle of the subsystem, # the client might not even know about the existence of the subsystem. This # approach lets you keep the complexity under control. defclient_code(facade) print facade.operation end
# The client code may have some of the subsystem's objects already created. In # this case, it might be worthwhile to initialize the Facade with these objects # instead of letting the Facade create new instances. subsystem1 = Subsystem1.new subsystem2 = Subsystem2.new facade = Facade.new(subsystem1, subsystem2) client_code(facade)
output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
在 Swift 中使用模式
复杂度: ★☆☆
流行度: ★★☆
使用示例: 使用 Swift 开发的程序中会经常使用外观模式。 它在与复杂程序库和 API 协作时特别有用。
/// The Facade class provides a simple interface to the complex logic of one or /// several subsystems. The Facade delegates the client requests to the /// appropriate objects within the subsystem. The Facade is also responsible for /// managing their lifecycle. All of this shields the client from the undesired /// complexity of the subsystem. classFacade {
/// Depending on your application's needs, you can provide the Facade with /// existing subsystem objects or force the Facade to create them on its /// own. init(subsystem1: Subsystem1=Subsystem1(), subsystem2: Subsystem2=Subsystem2()) { self.subsystem1 = subsystem1 self.subsystem2 = subsystem2 }
/// The Facade's methods are convenient shortcuts to the sophisticated /// functionality of the subsystems. However, clients get only to a fraction /// of a subsystem's capabilities. funcoperation() -> String {
var result ="Facade initializes subsystems:" result +=" "+ subsystem1.operation1() result +=" "+ subsystem2.operation1() result +="\n"+"Facade orders subsystems to perform the action:\n" result +=" "+ subsystem1.operationN() result +=" "+ subsystem2.operationZ() return result } }
/// The Subsystem can accept requests either from the facade or client directly. /// In any case, to the Subsystem, the Facade is yet another client, and it's /// not a part of the Subsystem. classSubsystem1 {
/// The client code works with complex subsystems through a simple interface /// provided by the Facade. When a facade manages the lifecycle of the /// subsystem, the client might not even know about the existence of the /// subsystem. This approach lets you keep the complexity under control. classClient { // ... staticfuncclientCode(facade: Facade) { print(facade.operation()) } // ... }
/// Let's see how it all works together. classFacadeConceptual: XCTestCase {
functestFacadeConceptual() {
/// The client code may have some of the subsystem's objects already /// created. In this case, it might be worthwhile to initialize the /// Facade with these objects instead of letting the Facade create new /// instances.
let subsystem1 =Subsystem1() let subsystem2 =Subsystem2() let facade =Facade(subsystem1: subsystem1, subsystem2: subsystem2) Client.clientCode(facade: facade) } }
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Sybsystem1: Ready! Sybsystem2: Get ready!
Facade orders subsystems to perform the action: Sybsystem1: Go! Sybsystem2: Fire!
/// Facade Design Pattern /// /// Intent: Provides a simplified interface to a library, a framework, or any /// other complex set of classes.
classFacadeRealWorld: XCTestCase {
/// In the real project, you probably will use third-party libraries. For /// instance, to download images. /// /// Therefore, facade and wrapping it is a good way to use a third party API /// in the client code. Even if it is your own library that is connected to /// a project. /// /// The benefits here are: /// /// 1) If you need to change a current image downloader it should be done /// only in the one place of a project. A number of lines of the client code /// will stay work. /// /// 2) The facade provides an access to a fraction of a functionality that /// fits most client needs. Moreover, it can set frequently used or default /// parameters.
/** * The Facade class provides a simple interface to the complex logic of one or * several subsystems. The Facade delegates the client requests to the * appropriate objects within the subsystem. The Facade is also responsible for * managing their lifecycle. All of this shields the client from the undesired * complexity of the subsystem. */ classFacade { protectedsubsystem1: Subsystem1;
protectedsubsystem2: Subsystem2;
/** * Depending on your application's needs, you can provide the Facade with * existing subsystem objects or force the Facade to create them on its own. */ constructor(subsystem1: Subsystem1 = null, subsystem2: Subsystem2 = null) { this.subsystem1 = subsystem1 || newSubsystem1(); this.subsystem2 = subsystem2 || newSubsystem2(); }
/** * The Facade's methods are convenient shortcuts to the sophisticated * functionality of the subsystems. However, clients get only to a fraction * of a subsystem's capabilities. */ publicoperation(): string { let result = 'Facade initializes subsystems:\n'; result += this.subsystem1.operation1(); result += this.subsystem2.operation1(); result += 'Facade orders subsystems to perform the action:\n'; result += this.subsystem1.operationN(); result += this.subsystem2.operationZ();
return result; } }
/** * The Subsystem can accept requests either from the facade or client directly. * In any case, to the Subsystem, the Facade is yet another client, and it's not * a part of the Subsystem. */ classSubsystem1 { publicoperation1(): string { return'Subsystem1: Ready!\n'; }
/** * Some facades can work with multiple subsystems at the same time. */ classSubsystem2 { publicoperation1(): string { return'Subsystem2: Get ready!\n'; }
/** * The client code works with complex subsystems through a simple interface * provided by the Facade. When a facade manages the lifecycle of the subsystem, * the client might not even know about the existence of the subsystem. This * approach lets you keep the complexity under control. */ functionclientCode(facade: Facade) { // ...
console.log(facade.operation());
// ... }
/** * The client code may have some of the subsystem's objects already created. In * this case, it might be worthwhile to initialize the Facade with these objects * instead of letting the Facade create new instances. */ const subsystem1 = newSubsystem1(); const subsystem2 = newSubsystem2(); const facade = newFacade(subsystem1, subsystem2); clientCode(facade);
Output.txt: 执行结果
1 2 3 4 5 6
Facade initializes subsystems: Subsystem1: Ready! Subsystem2: Get ready! Facade orders subsystems to perform the action: Subsystem1: Go! Subsystem2: Fire!
Starting add money to wallet Account Verified SecurityCode Verified Wallet balance added successfully Sending wallet credit notification Make ledger entry for accountId abc with txnType credit for amount 10
Starting debit money from wallet Account Verified SecurityCode Verified Wallet balance is Sufficient Sending wallet debit notification Make ledger entry for accountId abc with txnType debit for amount 5