Detailed explanation of three design patterns of Java using IOC control inversion

For many developers, Control inversion (IOC) is a fuzzy concept because they are rarely or never applied in the real world. In the best case, control inversion (IOC) can be considered as equivalent to dependency injection (DI). In fact, both flip control and dependency injection are considered equivalent only when they only reflect flip dependency management control. Although dependency injection is actually a well-known form of IOC, in fact, IOC is a relatively broader software design example, which can be implemented through a variety of modes. In this paper, We will introduce how dependency injection, observer pattern and template method pattern can achieve control inversion.

Just as many other design patterns are summarized from various use scenarios, the implementation of IOC is a similar compromise suitable for developers:

On the one hand, the design of highly decoupled components and the encapsulation of application logic in a single place are a direct and natural way to realize IOC@ H_ 301_ 5@ on the other hand, the above implementation needs to build at least one indirection layer, but in some use cases, this may be an over design@ H_ 301_ 5@ next, let's look at some specific implementations, which will help you understand how to make trade-offs between these attributes.

IOC paradigm unveiling @ h_ 301_ 5@

Inversion of control is a pattern with certain characteristics. Next, a classic IOC example given by Martin Fowler is given. The function of this example is to collect user data from the console@ H_ 301_ 5@

In this use case, process control is carried out in the main method: in the infinite loop call, the user input is read and the read content is output to the console. The main method completely controls when to read user input and when to output.

Consider a new version of the above program. In this version, user input needs to be received through the text box in the graphical interface. In addition, there is a button bound with an action listener. In this way, each time the user clicks the button, the input text is collected by the listener and printed to the panel.

In this version of the program, It is actually made up of the event listener model Under the control of (in this case, this is the framework), call the code written by the developer to read and print user input. In short, the framework will call the developer's code, not otherwise. The framework is actually an extensible structure, which provides developers with a set of entry points to inject custom code segments.

In this case, the control has been effectively reversed.

From a more general point of view, each callable extension point defined by the framework (in the form of interface implementation and implementation inheritance (also known as subclass) is a clearly defined form of IOC.

Take a look at the following simple servlet example: @ h_ 301_ 5@

Here, the httpservlet class (belonging to the framework) is an element that completely controls the program, rather than the subclass myservlet. After being created by the servlet container, when the get and post HTTP requests of the servlet are received, the code in the doget() and dopost() methods will be called automatically respectively.

Compared with the typical inheritance method, that is, the subclass is the control element rather than the base class. In this example, the control has been reversed.

In fact, the servlet method is the implementation of the template method pattern, which we will discuss in depth later.

When using frameworks that adhere to the opening and closing principle by providing extensible APIs, the role of developers using the framework is finally reduced to defining their own set of custom classes, that is, developers either implement one or more interfaces provided by the framework or inherit existing base classes. Conversely, instances of classes are instantiated directly by the framework, and these instances are called by the framework.

Fowler's words are quoted here: the framework calls developers, not developers. Therefore, IOC is often called the Hollywood principle: don't call us, we'll call you.

IOC implementation method @ h_ 301_ 5@

In this problem, it is obvious that there are several different ways to realize control inversion. Let's summarize the common implementation methods.

Injection dependency implementation IOC@H_301_5 @As mentioned earlier, injection dependency is an implementation of IOC and the most common object-oriented design method. But think about it: how does injection dependency achieve the effect of control reversal?

To answer this question, we give the following original example: @ h_ 301_ 5@

The userqueue interface defines a public API for storing user objects in a queue (for simplicity, the specific implementation of user is ignored here). Abstractuserqueue provides some public method implementations for subsequent inheritance classes. The last userfifoqueue and userlifoqueue implement FIFO and LIFO queues respectively.

This is an effective way to realize subclass polymorphism. But what exactly does it use to buy our benefits? In fact, there are many benefits.

By creating a client class that depends on the abstract type of userqueue (also known as the service in di terminology), different implementations can be injected at runtime without refactoring the code using the client class: @ h_301_5@

Userprocessor shows that injecting dependencies is indeed a way of IOC.

We can directly instantiate in the constructor through some hard coding methods, such as new operation, and obtain the dependency on the queue in userprocessor. However, this is a typical hard code programming, which introduces the strong coupling between client classes and their dependencies, and greatly reduces the testability. The alarm bell sounded in my ear! isn't it? Yes, this design is really frustrating.

This class declares a dependency on the abstract class userqueue in the constructor. In other words, the dependency is no longer operated by using new in the constructor. On the contrary, through external injection, either the dependency injection framework (such as CDI and Google Guice) or the factory or builders mode is used.

In short, with Di, the control of the dependencies of client classes is no longer located in these classes; But in the injector: @ h_ 301_ 5@

The above method achieves the expected effect, and the injection of userlifoqueue is also simple and clear. Obviously, Di is indeed a way to implement IOC (in this case, Di is an intermediate layer to implement IOC).

Observer mode implementation IOC@H_301_5 @

It is also a common intuitive way to implement IOC directly through observer mode. Broadly speaking, IOC is implemented through the observer, which is similar to the action listener in the GUI interface mentioned earlier. However, in the case of using the action listener, the call occurs only when a specific user event occurs (mouse click, keyboard or window event, etc.). The observer mode is usually used to track the change of the state of the model object in the context of the model view.

In a typical implementation, one or more observers are bound to observable objects (also known as topics in schema terms), for example, by calling the addobserver method. Once the binding between the observed and the observer is defined, the change of the observed state will trigger the operation of calling the observer.

In order to understand this concept in depth, the following example is given: @ h_ 301_ 5@

When the value changes, it triggers the call to the simple observer described above. In reality, APIs with more functions are usually provided, such as saving changed instances or old and new values, but these do not need to observe the action mode, so the example here should be as simple as possible.

Next, an observer class is given: @ H_ 301_ 5@

In the user class, when its state is changed through the setter method, it will trigger the call to the observer bound to it.

Using topic observers and topics, the following is an example of how to observe: @ h_ 301_ 5@

Whenever the state of the user object is modified through the setter method, the observer will be notified and a message will be printed to the console. So far, a simple use case of the observer pattern has been given. However, through this seemingly simple use case, we understand how control can be reversed in this case.

In observer mode, The theme plays the role of "framework layer", which completely dominates when and where to trigger whose call. The initiative of the observer is released, because the observer cannot dominate when to be called (as long as they have been registered in a theme). This means that in fact, we can find the "place" where the control is reversed "C - C when an observer is bound to a topic: @ h_301_5@

The above use cases briefly explain why observer mode (or action listener in Gui driven environment) is a very simple way to implement IOC. It is in the form of decentralized design of software components that control can be reversed.

IOC is realized through template method mode

The idea of template method pattern implementation is to define a general algorithm through several abstract methods (also known as algorithm steps) in a base class, and then let subclasses provide specific implementation, so as to ensure that the algorithm structure remains unchanged.

We can apply this idea to define a general algorithm to deal with domain entities: @ H_ 301_ 5@

Processentity () method is a template method, which defines the algorithm for processing entities, and abstract methods represent the steps of the algorithm, which must be implemented in subclasses. Several algorithm versions can be implemented by inheriting entityprocessor multiple times and implementing different abstract methods.

Although this makes clear the motivation behind the template method pattern, people may want to know why this is the IOC pattern.

In a typical inheritance, a subclass calls a method defined in the base class. In this mode, the relatively real situation is that the method (algorithm step) implemented by the subclass is called by the template method of the base class. Therefore, control is actually done in the base class, not in subclasses@ H_ 301_ 5@ this is also a typical example of IOC, which is implemented through a hierarchical structure. In this case, the template method is just a beautiful name for the adjustable extension point, which is used by developers to manage their own series of implementations.

Summary @ h_ 301_ 5@

Although inversion of control generally exists in the Java ecosystem, especially many frameworks generally adopt dependency injection, this model is still very vague for most developers, and its application is also limited by dependency injection. In this article, I illustrate this concept by showing several practical ways to implement IOC.

Dependency injection: the control of obtaining dependencies from the client no longer exists in these classes. It is handled by the underlying injector / di framework@ H_ 301_ 5@ observer mode: when the subject changes, control is transferred from the observer to the subject@ H_ 301_ 5@ template method pattern: control occurs in the base class that defines the template method, not in the subclass that implements the algorithm steps@ H_ 301_ 5 @ as usual, how and when to use IOC is determined by the analysis of each use case. Don't use IOC for IOC's sake.

The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>