Ii. application Patterns of dependency injection
We learned about the basic concepts of dependency injection and a brief introduction to some of the dependency injection frameworks, which we discuss primarily as a design idea for developers to use dependency injection frameworks to implement dependency injection.
1. The way of dependency injection
As we mentioned earlier, the so-called "dependency" is the simplest way to interpret a member variable in a Java class. As we all know, the method of assigning a value to a private member variable in a class usually has three methods: by constructor construction method, by setter method, by setting the visibility of private variable to true through the reflection mechanism. Similarly, the dependency injection framework uses these three ways to accomplish the set of dependent objects, which we call constructor injection, setter injection, member variable injection, respectively.
Here are two points to note. One is that in addition to these three common injection methods, there are other injection methods, such as the Lookup-method represented by the spring framework, called the "adorner" mode, and the method parameter injection like Guice, which we will not discuss in detail here. The second is that not all of the dependency injection frameworks provide these three common injections, such as the seam2.x version, which does not support constructor injection mode.
1.1. Constructor Injection
With constructor injection, the injection point is declared on the constructor of the dependency class, and the object to be injected is the parameter of the constructor.
Let's take a look at the example of the spring framework. First we declare the bank and Depositbook two dependent classes as a spring container-managed component:
@Component//Declare this dependency as spring component Public class BANKICBC implements Bank {//...} @Component//Declare this dependency as spring component Public class DEPOSITBOOKICBC implements Depositbook {//...} |
|
Here we use the @component method provided by spring 3.x to declare the spring components, and of course there are many other ways, which are not elaborated in detail. After these two dependencies are declared as components managed by the spring container, they can be supplied by the container to the dependents when needed. For example, in the Depositor depositor class, we define a dependency request with constructor as the injection point:
@Component Public class depositor { @Autowired//Constructor injection point Public Depositor (Bank bank, Depositbook Depositbook) { this. Bank = Bank; this. Depositbook = Depositbook; } Private Bank Bank; Private Depositbook Depositbook; Public Cash Withdraw (BigDecimal amount) { return Bank.withdraw (Depositbook, amount); } } |
|
After the main program calls the Depositor class, the container will automatically set up the dependent objects to be distributed to the main program.
Public void Runspringconstructordi () { Annotationconfigapplicationcontext context = New Annotationconfigapplicationcontext ("tutorial.di.ch01"); depositor depositor = Context.getbean (depositor. Class); Depositor.withdraw (new BigDecimal (10000)); } |
|
1.2. Setter Injection
The second common method of declaring injection points is setter injection, which is that the dependency injection framework uses the reflection mechanism to invoke the setter method of the dependency class to complete the dependency injection.
Let's look at examples of using the seam framework. The first is to declare the bank and Depositbook two dependent classes as components managed by the seam container:
@Name ("bank") Public class BANKICBC implements Bank {//...} @Name ("Depositbook") Public class DEPOSITBOOKICBC implements Depositbook {//...} |
|
The injection point is then declared at the setter method in the Depositor class of the dependent person:
@Name ("depositor") Public class depositor { Private Bank Bank; Private Depositbook Depositbook; @In//Bank Setter Injection Point Public void Setbank (Bank bank) { this. Bank = Bank; } Setter injection point for @In//Depositbook Public void Setdepositbook (Depositbook depositbook) { this. Depositbook = Depositbook; } Public Cash Withdraw (BigDecimal amount) { return Bank.withdraw (Depositbook, amount); } } |
|
Note that the seam framework defaults to injecting a dependency object that is bound to an identifier with the same name as the dependency field, and if you want to inject an identifier that is different from the field name to rely on the object, you need to use a syntax such as @in ("dependent object identifier").
1.3. Member Variable injection
Member variable injection refers to the dependency injection framework that uses the reflection mechanism to directly set the member variable of the dependency class to the container-managed dependent object.
In the case of the seam framework, however, the only difference with the setter injection pattern is to label @in next to the member variable instead of its setter method.
@Name ("depositor") Public class depositor { @In//Bank member variable injection point Private Bank Bank; Member variable injection points for @In//Depositbook Private Depositbook Depositbook; Public Cash Withdraw (BigDecimal amount) { return Bank.withdraw (Depositbook, amount); } } |
|
1.4. Choice of injection mode
This is a very broad topic in terms of how to use the injection patterns described earlier and under what circumstances. Here's a simple example to illustrate, such as designing an immutable (final) dependent class, you must use the constructor injection method:
@Component Public class depositor { @Autowired//Constructor injection point Public Depositor (Bank bank, Depositbook Depositbook) { this. Bank = Bank; this. Depositbook = Depositbook; } Private Final Bank Bank; Immutable dependencies Private Final Depositbook Depositbook; Immutable dependencies Public Cash Withdraw (BigDecimal amount) { return Bank.withdraw (Depositbook, amount); } } |
|
If a class has too many dependencies, and the developer does not want to construct the parameter of the method as an "overly long parameter list" (an anti-pattern that affects the readability and maintainability of the code, Martin Fowler in 1999 in its refactoring:improving Design of Existing Code), you can consider setter injection or member variable injection. In addition, if a similar "cyclic dependency" is encountered, such as host and parasitic animals, which are interdependent "cyclic dependent" patterns, we may need to constructor and setter two mixed patterns to resolve. In a word, choosing a dependency injection pattern is a big topic, and we're not going to talk about it in depth.
Dependency Injection and AOP Brief (v)-the way of dependency injection.