public class CameraMan {
Camera camera;
public void shoot() {
camera = new StillCamera();
camera.action();
}
}
public interface Camera{
public void action();
}
public class StillCamera implements Camera{
public void action() {
System.out.println(“ take Picture”);
}
}
Here, you saw how class CameraMan got rid of explicit reference to the StillCamera object by using interface. It means in future, if CameraMan decided to use different type of camera, say VideoCamera, those reference and reference call remains the same resulting minimal modification required. However, this implementation is still not free of coupling. CameraMan still has the control of creating StillCamera. Now let's look at following snippets which adds a new class Container to resolve the coupling problem so that CamereMan class becomes independent and reusable.
public class CameraMan {
Camera camera;
public CameraMan(Camera camera) {
this.camera = camera;
}
public void shoot() {
camera.action();
}
}
public interface Camera{
public void action();
}
public class StillCamera implements Camera{
public void action() {
System.out.println(“ take Picture”);
}
}
public class Container{
private Map components;
public Container(){
components = new HashMap();
StillCamera sCamera = new StillCamera();
components.put("camera", sCamera);
CameraMan cMan = new CameraMan(sCamera);
components.put("cameraman", cMan);
}
public Object getComponent(String id){
return this.components.get(id);
}
}
public class MainClass{
public static void main(String[] str) {
Container container = new Container();
CameraMan cMan = container.getComponent("cameraman");
CMan.shoot();
}
}
Finally, you most have noticed the inversion of control. Now you can just call the CameraMan as show in MainClass, to shoot the picture. CameraMan doesn't have to worry about creating camera object, Container class will create them and inject into the CameraMan. Therefore, by adding new component to create and manage rest of the components, we made other components light weighted and free from coupling problem which resulted reusable components. Such new component that resolves the dependency resolution and controls the creation and management of our reusable components and their life cycle is call Container class.
The term Dependency Injection (DI) is another phrase used interchangeably to define IoC. Many writers have distinguished between these two with IoC as design principle and DI as one of the patterns to implement IoC. There are three ways to implement IoC using DI pattern, depending upon how you wire up the dependent components inside Container class: Contructor Injection, Setter Injection and Interface Injection.
Constructor Injection
1. Dependency injected via constructor.
2. Prevents careless modification problem as once injected, can't be modified.
3. Since all dependencies are injected using constructor's arguments, avoids possibilities of missing initialization
4. However, shortcoming are: JVM unable to add default constructor, you have definite explicitly. Also if component has lots of dependencies, a constructor's argument list get too long reducing code readability.
5. The Container class as shown above implements IoC using Constructor Injection.
6. Spring is a open source application framework whose container class support Constructor Injection. I recommend using such framework instead of building your own Container class. Following is the snippets showing spring's way of implementing IoC by constructor injection using XML configuration. Please refer to spring resources
public class MainClass{
public static void main(String[] str) {
public static void main(String[] str) {
ApplicationContent actx = new ClassPathXMLApplicationContent("spring.xml");
CameraMan cMan = (CameraMan)actx.getBean("cameraman");
cMan.shoot();
}}
spring.xml
......
......
......
.....
.....
Setter Injection
1. This the most popular DI pattern.
2. Injects the dependencies via setter method declared in a component.
3. Following is the example of Container class that depicts such DI.
public class Container{
private Map components;
public Container(){
components = new HashMap ();
StillCamera sCamera = new StillCamera();
components.put("camera", sCamera);
CameraMan cMan = new CameraMan();
private Map components;
public Container(){
components = new HashMap
StillCamera sCamera = new StillCamera();
components.put("camera", sCamera);
CameraMan cMan = new CameraMan();
cMan.setCamera(sCamera);
components.put("cameraman", cMan);
}
public Object getComponent(String id){
return this.components.get(id);
}
}
}
public Object getComponent(String id){
return this.components.get(id);
}
}
public class CameraMan {
Camera camera;
public void setCamera(Camera camera) {
this.camera = camera;
}
public void shoot() {
camera.action();
}
}
Camera camera;
public void setCamera(Camera camera) {
this.camera = camera;
}
public void shoot() {
camera.action();
}
}
4. Spring framework also supports Setter Injection. Here is a same example as above that uses spring's DI using XML configuration. Please refer to spring resource
for more detail.
public class CameraMan {
Camera camera;
public void setCamera(Camera camera) {
this.camera = camera;
}
public void shoot() {
camera.action();
}
}
Camera camera;
public void setCamera(Camera camera) {
this.camera = camera;
}
public void shoot() {
camera.action();
}
}
spring.xml
.......
.......
.......
....
Interface Injection1. This type is rarely or seldom used.
2. Shortcomings: requires all the compoments implements particular interface for the container to inject dependency. Since interface is container specific, components have to rely on the container and cannot be reused outside its scope.
3. Following is the same example implementing IoC using Interface Injection.
public interface Injectable{
public void inject(Man
}
public class CameraMan implements Injectable {
private Camera camera;
public void inject(Map
camera = (Camera)components.get("stillcamera")
}}
public class Container{
private Map components;
public Container(){
components = new HashMap();
StillCamera sCamera = new StillCamera();
components.put("camera", sCamera);
CameraMan cMan = new CameraMan();
private Map components;
public Container(){
components = new HashMap
StillCamera sCamera = new StillCamera();
components.put("camera", sCamera);
CameraMan cMan = new CameraMan();
cMan.inject(components);
components.put("cameraman", cMan);
}
public Object getComponent(String id){
return this.components.get(id);
}
}
}
public Object getComponent(String id){
return this.components.get(id);
}
}
This is all about Inversion of Control and way to implement using Dependency Injection pattern. Hope this is simple enough.
No comments:
Post a Comment