This article
discusses dependency injection in a tutorial format. It covers some of the
newer features of Spring DI such as annotations, improved XML configuration and
more.
Dependency
Injection
Dependency Injection (DI) refers to
the process of supplying an external dependency to a software component. DI can
help make your code architecturally pure. It aids in design by interface as
well as test-driven development by providing a consistent way to inject
dependencies. For example, a data access object (DAO) may depend on a database
connection. Instead of looking up the database connection with JNDI, you could
inject it.
One way to think about a DI container like Spring is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get its job done (dependencies), a DI container injects those dependent objects. This is the so-called Hollywood Principle, “Don't call us” (lookup objects), “we’ll call you” (inject objects).
If you have worked with CRC cards you can think of a dependency as a collaborator, i.e., an object that another object needs to perform its role.
Let's say that you have an automated teller machine (ATM) and it needs the ability to talk to a bank. It uses what it calls a transport object to do this. In this example, a transport object handles the low-level communication to the bank.
This example could be represented by either of the two interfaces as follows:
AutomatedTellerMachine interface
One way to think about a DI container like Spring is to think of JNDI turned inside out. Instead of an object looking up other objects that it needs to get its job done (dependencies), a DI container injects those dependent objects. This is the so-called Hollywood Principle, “Don't call us” (lookup objects), “we’ll call you” (inject objects).
If you have worked with CRC cards you can think of a dependency as a collaborator, i.e., an object that another object needs to perform its role.
Let's say that you have an automated teller machine (ATM) and it needs the ability to talk to a bank. It uses what it calls a transport object to do this. In this example, a transport object handles the low-level communication to the bank.
This example could be represented by either of the two interfaces as follows:
AutomatedTellerMachine interface
package com.arcmind.springquickstart;
import java.math.BigDecimal;
public interface AutomatedTellerMachine {
void deposit(BigDecimal
bd);
void withdraw(BigDecimal
bd);
}
ATMTransport interface
package com.arcmind.springquickstart;
public interface ATMTransport {
void communicateWithBank(byte [] datapacket);
}
Now the
AutomatedTellerMachine needs a transport to perform its intent, namely withdraw
money and deposit money. To carry out these tasks, the AutomatedTellerMachine
may depend on many objects and collaborates with its dependencies to complete
the work.
An implementation of the AutomatedTellerMachine may look like this:
An implementation of the AutomatedTellerMachine may look like this:
AutomatedTellerMachine implementation:
package com.arcmind.springquickstart;
import java.math.BigDecimal;
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{
private ATMTransport
transport;
public void deposit(BigDecimal bd) {
...
transport.communicateWithBank(...);
}
public void withdraw(BigDecimal bd) {
...
transport.communicateWithBank(...);
}
public void setTransport(ATMTransport transport) {
this.transport =
transport;
}
}
The AutomatedTellerMachineImpl does not know or care how the transport
withdraws and deposits money from the bank. This level of indirection allows us
to replace the transport with different implementations such as in the
following example:
Three example transports: SoapAtmTransport, StandardAtmTransport and SimulationAtmTransport
Three example transports: SoapAtmTransport, StandardAtmTransport and SimulationAtmTransport
package com.arcmind.springquickstart;
public class SoapAtmTransport implements ATMTransport {
public void communicateWithBank(byte[] datapacket) {
...
}
}
package com.arcmind.springquickstart;
public class StandardAtmTransport implements ATMTransport {
public void communicateWithBank(byte[] datapacket) {
}
}
package com.arcmind.springquickstart;
public class SimulationAtmTransport implements ATMTransport {
public void communicateWithBank(byte[] datapacket) {
...
}
}
Notice the possible
implementations of the ATMTransport interface. The AutomatedTellerMachineImpl
does not know or care which transport it uses. Also, for testing and
developing, instead of talking to a real bank, notice that you can use the
SimulationAtmTransport.

No comments:
Post a Comment