Façade design patterns. Remote Facade

Before reading, please review the following conventions and concepts. This article is updated with some frequency, so if you have read it before, it is not a fact that the data has not changed.

Facade belong to class structural patterns. Represents a unified interface instead of a set of interfaces of a certain subsystem. The façade pattern defines a higher-level interface that makes subsystems easier to use.

Dividing a complex system into subsystems allows you to simplify the design process, and also helps to minimize the dependencies of one subsystem on another. However, this leads to the fact that using such subsystems together becomes quite difficult. One way to solve this problem is to introduce a façade pattern.

This is one of those patterns that does not have a clear implementation, since it depends on the specific system. In general, we need to perform the following transformation:

The gray rectangle contains our subsystems, which have some dependencies among themselves (they may not). The top three blocks indicate the three sections of the client code in which it interacts with this subsystem. Our task is to make a simple, unified interface through which it would be enough to interact with subsystems within the framework of the task, those. we don’t need to make a universal interface for all occasions, since in most cases this is unnecessary and leads to more complex interactions and increased development time.

Below is a sketch of one implementation:

/** * SystemA */ class Bank ( public function OpenTransaction() () public function CloseTransaction() () public function transferMoney($amount) () ) /** * SystemB */ class Client ( public function OpenTransaction() ( ) public function CloseTransaction() () public function transferMoney($amount) () ) /** * SystemC */ class Log ( public function logTransaction() () ) class Facade ( public function transfer($amount) ( $Bank = new Bank(); $Client = new Client(); $Log = new Log(); $Bank->OpenTransaction(); $Client->OpenTransaction(); $Log->logTransaction("Transaction open"); $ Bank->transferMoney(-$amount); $Log->logTransaction("Transfer money from bank"); $Client->transferMoney($amount); $Log->logTransaction("Transfer money to client"); $Bank ->CloseTransaction(); $Client->CloseTransaction(); $Log->logTransaction("Transaction close"); ) ) // Client code $Transfer = new Facade(); $Transfer->transfer(1000);

Description of Remote Facade

Provides a common unifying interface to a set of object methods to improve networking efficiency.

The Remote Facade pattern in the object-oriented model improves work with small objects that have small methods. Small techniques offer big opportunities to control and change behavior and improve the client's understanding of the application. One consequence of this fine-grained behavior is that there is usually a lot of interaction between objects, with a lot of method calls.

In one address space, “fine-grained” interactions work well, but everything changes when interaction occurs between processes. Remote calls are more expensive because a lot needs to be done: sometimes data needs to be organized, checked for security, packets need to be routed on switches. If two processes operate at different ends of the world, even the speed of light can play a role. The hard truth is that any interprocess communication is orders of magnitude more wasteful than intraprocess calls. Even if both processes are running on the same machine. This performance impact cannot be overlooked, even by lazy optimization enthusiasts.

As a result, any object that is involved in remoting needs a more general interface that minimizes the number of requests required to do something. This affects not only methods, but also objects. Instead of requesting an invoice and all its items separately, you need to read and update all invoice items in one request. This affects the entire structure of the object. We must forget about the good purpose of small objects and small methods. Programming becomes more and more difficult, productivity falls and falls.

The Remote Facade pattern represents a general “Facade” (according to GoF) on top of a structure of more “fine-grained” objects. None of these objects have a remote interface, and the Remote Facade does not include any business logic. All Remote Facade does is translate general requests into a set of small requests to subordinate objects.

Last updated: 10/31/2015

Facade is a design pattern that hides the complexity of a system by providing a simplified interface for interacting with it.

When to use a façade?

    When you have a complex system and you need to simplify working with it. The facade will allow you to define one point of interaction between the client and the system.

    When you need to reduce the number of dependencies between the client and a complex system. Facade objects allow you to separate, isolate system components from the client and develop and work with them independently.

    When you need to define subsystems of components in a complex system. Creating facades for the components of each individual subsystem will simplify the interaction between them and increase their independence from each other.

In UML, the general diagram of a facade can be represented as follows:

A formal program definition in C# might look like this:

Class SubsystemA ( public void A1() () ) class SubsystemB ( public void B1() () ) class SubsystemC ( public void C1() () ) public class Facade ( SubsystemA subsystemA; SubsystemB subsystemB; SubsystemC subsystemC; public Facade(SubsystemA sa, SubsystemB sb, SubsystemC sc) ( subsystemA = sa; subsystemB = sb; subsystemC = sc; ) public void Operation1() ( subsystemA.A1(); subsystemB.B1(); subsystemC.C1(); ) public void Operation2 () ( subsystemB.B1(); subsystemC.C1(); ) ) class Client ( public void Main() ( Facade facade = new Facade(new SubsystemA(), new SubsystemB(), new SubsystemC()); facade. Operation1(); facade.Operation2(); ) )

Participants

    Classes SubsystemA, SubsystemB, SubsystemC, etc. are components of a complex subsystem with which the client must interact

    Client interacts with subsystem components

    Facade - directly a facade that provides an interface to the client for working with components

Let's consider using the pattern in a real problem. I think most programmers will agree with me that writing code in Visual Studio is a pleasure compared to how code was written before the advent of integrated development environments. We just write the code, press a button and that’s it - the application is ready. In this case, the IDE is a façade that hides the complexity of compiling and running an application. Now let's describe this facade in a C# program:

Class Program ( static void Main(string args) ( TextEditor textEditor = new TextEditor(); Compiller compiller = new Compiller(); CLR clr = new CLR(); VisualStudioFacade ide = new VisualStudioFacade(textEditor, compiller, clr); Programmer programmer = new Programmer(); programmer.CreateApplication(ide); Console.Read(); ) ) // text editor class TextEditor ( public void CreateCode() ( Console.WriteLine("Writing Code"); ) public void Save() ( Console.WriteLine("Saving code"); ) ) class Compiller ( public void Compile() ( Console.WriteLine("Compiling an application"); ) ) class CLR ( public void Execute() ( Console.WriteLine("Executing an application "); ) public void Finish() ( Console.WriteLine("Finishing the application"); ) ) class VisualStudioFacade ( TextEditor textEditor; Compiller compiller; CLR clr; public VisualStudioFacade(TextEditor te, Compiller compil, CLR clr) ( this. textEditor = te; this.compiller = compil; this.clr = clr; ) public void Start() ( textEditor.CreateCode(); textEditor.Save(); compiller.Compile(); clr.Execute(); ) public void Stop() ( clr.Finish(); ) ) class Programmer ( public void CreateApplication(VisualStudioFacade facade) ( facade.Start(); facade.Stop(); ) )

In this case, the system components are the TextEditor class, the Compiller class, and the common language runtime CLR class. The client is the programmer class, the facade is the VisualStudioFacade class, which, through its methods, delegates the work to components and their methods.

It should be taken into account that the client can, if necessary, access the components directly, for example, use a text editor separately from other components. But due to the complexity of the process of creating an application, it is better to use a facade. Also, this is not the only possible façade for working with these components. If necessary, you can create alternative facades, just as in real life we ​​can use alternative development environments.

The GoF book describes this pattern as providing a unified interface to multiple interfaces in some subsystem. Book " Design Patterns"gives the same interpretation and draws attention to the fact that, by hiding the complexity of the subsystem, the pattern" Facade" while providing all the capabilities of the subsystem through an easy-to-use interface.

For a simple practical example of how the Façade pattern works, imagine a washing machine with just two wash cycles: for heavily soiled laundry and for lightly soiled laundry.

For each mode, the washing machine must perform a predefined set of operations: set the water temperature, heat the water, set the wash cycle duration, add laundry detergent, add bleach, add fabric softener, etc. Each mode requires a different set of washing instructions (different amounts of detergent, higher/lower temperature, longer/shorter spin cycle, etc.).

The simple interface provides two wash modes, hiding the complex logic of choosing the appropriate water temperature, spin duration and wash cycle, as well as different methods for adding laundry detergent, bleach or fabric softener.

The user of a washing machine does not have to think about the complex logic of washing things (selecting temperature, cycle duration, etc.). The only thing the user has to do is decide whether the laundry is heavily soiled or not. This is essence of the "Facade" pattern in relation to the design of washing machines.

Pattern "Facade" usually implemented for the following purposes and cases:

  • to provide simple and unified access to the legacy production management system;
  • to create a public API for classes such as driver;
  • to provide coarse-grained access to available services. Services are grouped as in the washing machine example above;
  • to reduce the number of network calls. The facade makes multiple calls to the subsystem, while the remote client must make a single call to the facade;
  • to encapsulate the workflow and internal details of an application to ensure simplicity and security.

By the way, facades also sometimes implemented as abstract singleton factories.

Facade Class Diagram. As can be seen in the class diagram at Fig.3.1,The Façade pattern provides a simple interface to the underlying ,system while encapsulating complex logic.

Fig 3.1. Class diagram of the "Facade" pattern.

Facade is a structural design pattern that provides a simple interface to a complex class system, library, or framework.

Problem

Your code has to work with a large number of objects from some complex library or framework. You must initialize these objects yourself, ensure the dependencies are in the correct order, and so on.

As a result, the business logic of your classes is closely intertwined with the implementation details of third-party classes. Such code is quite difficult to understand and maintain.

Solution

A facade is a simple interface for working with a complex subsystem containing many classes. The facade may have a stripped-down interface that does not have 100% of the functionality that can be achieved by using a complex subsystem directly. But it provides exactly those features that the client needs and hides all the rest.

Facade is useful if you are using some complex library with a lot of moving parts, but you only need part of its capabilities.

For example, a program that uploads videos of cats to social networks can use a professional video compression library. But all the client code for this program needs is a simple encode(filename, format) method. By creating a class with this method, you implement your first facade.

Analogy from life


When you call a store and place an order over the phone, the customer service representative is your front door to all services and departments of the store. It provides you with a simplified interface to the order creation system, payment system and delivery department.

Structure



    Facade provides quick access to certain subsystem functionality. It “knows” which classes need to forward the request, and what data is needed for this.

    Additional façade can be introduced so as not to “clutter up” the single façade with heterogeneous functionality. It can be used by both the client and other facades.

    Complex subsystem consists of many different classes. In order to make them do something, you need to know the details of the subsystem structure, the order of initialization of objects, and so on.

    The subsystem classes do not know about the existence of the facade and work with each other directly.

    Client uses a facade instead of directly working with objects of a complex subsystem.

Pseudocode

In this example Facade simplifies work with a complex video conversion framework.


An example of isolating multiple dependencies in one façade.

Instead of working directly with a dozen classes, the facade provides the application code with a single method for converting video, which itself takes care of correctly configuring the necessary framework objects and obtaining the required result.

// Classes for a complex third-party video conversion framework. We // don't control this code, so we can't simplify it. class VideoFile // ... class OggCompressionCodec // ... class MPEG4CompressionCodec // ... class CodecFactory // ... class BitrateReader // ... class AudioMixer // ... // Instead, we create a Facade - a simple interface for working // with a complex framework. The facade does not have all the functionality // of the framework, but it hides its complexity from clients. class VideoConverter is method convert(filename, format):File is 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) // The application does not depend on a complex conversion framework / / video. By the way, if you suddenly decide to change the framework, you // will only need to rewrite the facade class. class Application is method main() is convertor = new VideoConverter() mp4 = convertor.convert("funny-cats-video.ogg", "mp4") mp4.save()

Applicability

When you need to present a simple or stripped-down interface to a complex subsystem.

Often subsystems become more complex as the program evolves. Applying most patterns results in smaller classes, but in larger numbers. It is easier to reuse such a subsystem, customizing it each time for specific needs, but at the same time, it becomes more difficult to use the subsystem without customization. The facade offers a certain type of system by default, which suits most clients.

When you want to decompose a subsystem into separate layers.

Use facades to define entry points to each level of the subsystem. If subsystems depend on each other, then the dependency can be simplified by allowing the subsystems to exchange information only through facades.

For example, let’s take the same complex video conversion system. You want to break it down into layers of audio and video work. For each of these parts, you can try to create a facade and have the audio and video processing classes communicate with each other through these facades, rather than directly.

Implementation steps

    Determine whether it is possible to create a simpler interface than that provided by the complex subsystem. You're on the right track if this interface eliminates the need for the client to know about subsystem details.

    Create a facade class that implements this interface. It must forward client calls to the correct subsystem objects. The façade will have to take care to initialize the subsystem objects correctly.

    You will get maximum benefit if the client works only with the facade. In this case, changes in the subsystem will affect only the facade code, and the client code will remain working.