📜 ⬆️ ⬇️

Proper use of the pattern "Bridge" (Two-way bridge) or MVC -> "Business entity - Visualization - Controller"

Prehistory

Article Wrong use of the design pattern "Bridge" / "Bridge" as it happened, divided the audience into two. Further, I thought, saying, And not to say B, it will be wrong. No, I do not give up my words, but I found where and how I used the “Bridge” pattern. Because it is also misunderstood, it seems the alternative name "Handle / Body" is less misleading.

So where? It turned out in my analogue of using the concept of MVC (Model / View / Controller).
')
Therefore, at first I will acquaint with my variation “Business entity - Visualization - Controller”. I already wrote it, but I think very few people are familiar with this. And then let's see where the “Right Bridge” is.

PS I was given a credit of trust here, and I undertook to write another article about improving the Flyweight pattern - I’ve written a report.



Separation of visualization and business logic

Model-view-controller is the most well-known principle of software architecture, in which the application data model, user interface, and control logic are divided into three separate components, so that modifying one of the components has minimal impact on other components. The description and some aspects, currently of a historical nature, are described in the article by Sergey Rogachev, “Generalized Model-View-Controller”, 2007. A few more examples in Ivan Bodyagin, Model-View-Controller in .Net and Andrey Ozerov, MVC Triad In action.

In reality, the use of this model is associated with a number of problems and applications built on this model, despite the declaration, are not flexible and have little connection. The very idea of ​​separating the visualization from the business logic is declared in it, but the connections between the model, the presentation and the controller are not built at all effectively.

Note that not every “Business entity” has a visualization, and as a rule, the same “Business entity” can, depending on the context, be used both with and without visualization. However, it should not lose its functionality because of this. Note that if the “Business entity” is used without visualization, then the creation of the objects of the view and the controller is completely unnecessary.

But sometimes a model (the so-called passive model) is really understood only as data (properties, methods of accessing it, retrieving it from a database) without business logic, then when separating such a model becomes useless by itself. Let us check the rationality of the classic model-view-controller-passive model, in most cases the implementation, if you don’t create the view and controller objects, the remaining model object will remain completely “paralyzed”, that is, it will not function. Thus, we see that the declaration of independence in this model is a fiction.

But later, ideas about the active model were developed, when a model is really understood as a business entity, as a collection of data and business logic. Then everything is in order, but you need to be extremely careful so that business logic is not left in the visualization classes or the controller.

Therefore, let's start with the fact that the separation of data from the actual methods (business logic) is unacceptable in the object-oriented approach, and as we can see, if this is not done, the model will not be functional (“paralyzed”). Therefore, in order not to be confused, we need to clarify at least the terminology and we will talk about the architectural principle called “Business entity - Visualization - Controller” instead of “Model-view-controller”. So far, we have changed only the words (then we will see that this is quite a matter of principle) and refused to consider the passive MVC model as not consistent.

Now let's look at the declaration for the Model-View-Controller model:

While the view and controller depend on the model, the model does not depend on either the view or the controller. This is a key feature of the separation, which allows you to work with the model, and therefore with the business logic of the application, regardless of the visual presentation.

But besides the independence of the model from the visual presentation, the opposite is often necessary. You must also have the independence of the visual representation of the model. And this in MVC is obtained by definition is impossible.

So first. The words representation depends on the model can mean one of two things:
visualization creates (generates) a model (business entity), and from the point of view of classes, visualization aggregates the business entity
(or a softer version) the controller creates both a model (business entity) and visualization. And then there are two options for how the controller uses links to these objects:
visualization receives a link to both the controller and the model, i.e. again the visualization aggregates the business entity
visualization receives a link only to the controller, but the controller contains delegate methods that are directly addressed to the model, i.e. Formally, visualization does not aggregate the business entity, but only the controller, but indirectly (since the controller in turn aggregates the model) again this leads to the aggregation of the business entity

Do not you think this is at least strange? It turns out that a business entity cannot decide how to visualize itself, and whether to visualize it at all. Moreover, the user (in this case, the application developer) has to create a visualization object or controller, and in some strange way has to work through a visualization or controller with a business entity. Although let's say visualization may not be required at all.

Therefore, the first thing we recognize is the wrong decision. Visualization, in spite of the fact that it is a rather specific action, is no more nothing less than just one of the functions of a business entity. And therefore, it is the business entity that must create the visualization object, aggregate it and decide when and with what object to visualize itself, and whether it should be done at all. But the object of visualization just should not know anything about the business entity and the controller, except for those data fields that the business entity wants to visualize using the interface.

But we still need to fulfill the principle condition:

Visualization classes contain only the logic that is needed to work with the user interface. And the business entity classes do not contain a visualization code, but they contain all the business logic.

So we need to separate the code that handles the user interface from the code that handles the business logic. While the behavior (methods) is relatively easy to divide into parts, which cannot be done with the data (fields, properties). The data must be in graphic elements and have the same meaning as the data in the domain model (business entity). Therefore, fields containing data should be duplicated and their synchronization should be ensured (for example, the value in the TextBox graphic element must be synchronized with the value of the business entity field). Such synchronization requires two-way communication between the objects of visualization and the business entity. Therefore, with respect to data fields, it is fundamentally impossible to separate these two objects. But first, it can be limited only by data fields, and secondly, it can be made transparent for the object of visualization.

In C #, the current technology WPF is used for visualization, which provides a binding mechanism. Therefore, it remains only to specify which properties will be interconnected. And there is a dilemma - in what object should it be done? If we register this in a business entity, then we break the rule. Business entity classes do not contain visualization code. If it is prescribed in a visualization class, then we break the rule. The visualization classes contain only the logic that is needed to work with the user interface. In the model “model-view controller”, however, this is often prescribed in the visualization class.

But we will proceed differently. One of the reasons for the introduction of the third, seemingly completely redundant class - the controller, is precisely the one indicated above. But first, let's try to clarify what a controller is in itself, and when it is created. The controller in the model “Business entity - Visualization - Controller” is essentially a protocol of interaction between the business entity and its visualization. At the same time, when a business entity determines that it needs to be visualized somehow, it selects and creates an object of a certain visualization class, then creates one or another interaction protocol - the controller. At the same time, when creating a controller, it gives it two links to itself and to the selected visualization. After that, the business entity is theoretically (practically nonetheless difficult to achieve this completely) should no longer work with the object of visualization, or with the controller itself, thereby ensuring complete independence.

It turns out that the controller, when initializing, prescribes the binding, associating visual fields with the fields of the business entity, after which formally these two objects of the visualization and the business entity are synchronized in accordance with the selected protocol, but there is no other interaction between them. This approach is called transparent communication, that is, there is no direct interaction, and only interaction occurs according to the protocol - the code that is registered in the controller.

If another programming language is used, and there is no way to use binding, you can replace it with a refactoring technique, which is called “Duplicate Observed Data” [1].

But you can implement the binding yourself, it's not very difficult. First you need to recognize that data synchronization between the model and the visualization is a low-level function that must be performed by a separate class MySynh. How to write it? The controller has a link to both the model and the visualization. It transmits these links to MySynh. In addition, purely in a declarative form it registers the connections of the form FieldVisualization A = Property Model B, purely by text. Access methods get (), set () are written on each property in the model and visualization - in which, in addition to the actual assignment of a new value, an event of the type Changed FieldA is generated. This is necessary not only for synchronization, but also for calling the logic for changing values. Therefore, it is in any case. What remains is, when MySynh is initialized, it subscribes to all events whose synchronization was told it cares about. When the event of a change in value actually occurs, he receives a call, searching through his database about which connections must be maintained and finds the necessary one. And using the "reflection" (get a link to the property by its textual name) assigns a new value.

As a result, the data in the model and visualization are always synchronized, always the same. And not the one, not the other does not have links to each other. Those. they are completely independent and do not know about the existence of each other.

Now the second. In addition to transparent data synchronization, it is necessary to ensure separation of behavior (methods). There is essentially a different logic - the logic of visualization (for example, pressing a button can somehow color, make certain fields available or visible), and business logic (for example, certain values ​​are calculated from the entered data). Provide the visualization logic needed in the visualization class, and the business logic, respectively, in the business entity. This is not always trivial, but this should be given significant attention. The difficulty arises in the fact that the signal from the user is the only one - for example, pressing a button, and you need to call two or more independent methods. At the same time, we cannot call the business entity methods from the visualization object so as not to violate our basic principles of separation.

And again here you need to use a controller. But if for data we used the capabilities of binding, then in this case we need to use the event technique. Then again when the controller is initialized, it associates the signals from the visual interface with the methods of the business entity, and again instead of a direct strict connection we get a transparent connection.

Thus, we need a controller as a link between the business entity and the visualization. And in this case, we really have almost completely independent classes of business entities and visualizations, and choosing the appropriate controller we can use different business entities and visualizations in any combination. At the same time, compared with the classical “Model-View-Controller” scheme, we can not only have different visualizations for the business entity, but also display different business entities with a specific visualization. Not to mention the problems indicated above. With such an organization, we get the true separation of visualization from business logic in both directions. As well as the business entity is still able to make a decision about the visualization itself simply by using one or another controller to communicate with one or another visualization.

This text may be difficult to understand. Here one good person wrote with my assistance, perhaps a more understandable description of my idea. With code examples.

Controller and there is a bridge

If you look for a “bridge” here, it turns out that the controller has two references to two “bodies”. One on the "Business entity", the second on the "Visualization". Why did he find himself here if, as I stated in the first article, the “division into abstraction and implementation” is harmful.

And all because the controller is not quite a realization, and not exactly an abstraction. Abstraction and implementation here are together as it should be in the “business entity”. But a certain logic of communication of visualization with business logic is brought into the controller. This communication logic is what is well carried into the bridge. In fact, visualization is part of some implementation of the “business entity”, but very special. And when we separate it, it is very good to develop the “User Interface” and “Business Logic” separately in different hierarchies. But through the controller to connect them. This is the correct use of the “Bridge” pattern. But this is like a “Two-way bridge”, on the one hand we run to business logic (whole), and on the other to “visualization”

Source: https://habr.com/ru/post/138461/


All Articles