Thursday, January 26, 2012

Dependency Injections.

The use of a factory class is one common way to implement a dependency injection.


For example consider the class below

class Human

{

HumanRace race;

Human()

{

race = new AsianRace();

}

}

There is an eminent issue in the above code. We observe that upon instantiation of the above class , the interface HumanRace would be injected with a reference to the class AsianRace (). And we were given no choice or anything. We have no power to control a decision inside. We can however do the following

class Human

{

HumanRace race;

Human(String type)

{

If(type.compareTo(“Asian”)

race = new AsianRace();

Else if(type.compareTo(“Scandinavian”)

race = new ScandinavianRace();

}

}

Now in resolving a problem, we have created yet another one. We have succeeded only in painting an issue with another one. A granddaddy of OOP rule “Encapsulate the changes”. We can see that every time a new race would be introduced (perhaps new species of human found off the Bermuda coast) , we’d have to change our class code. This sucks. Our code is not at all extendible. If our awesome human detecting application is deployed at some organization, we’d have to recall it back; change the code;compile-test-debug-build; then send it over again. Just to know that the researchers have found yet another race for us, and we need to go through the above again. So this is why the OOP rule “Encapsulate the changes” exists. If we keep changing our main class, that code will bound to break at other places because that class in question would be actively in use. We do not want to introduce changes in that. Rather a change making agent should be separated.

Introducing Factory Pattern

Okay so here goes. We will attempt to resolve the above issue by encapsulating the changes. But as always , a resolution of a problem becomes a breeding ground for another. Perhaps this is why we still see new advancements in everything. Had mankind ever made a DEAD TO THE POINT solution to a problem , progress would have halted all of a sudden. Anyways we would introduce factory pattern now. We would be able to inject a dependency and along that we would be encapsulating the changes. This ought to resolve our issues.

Abstract class Human

{

HumanRace race;

Human()

{

}

Public void InstatiateRace(String type)

{

race= createRace(type);

}

Abstract HumanRace createRace(String raceType);

}

Class HumanFactory extends Humans

{

HumanRace createRace(String raceType)

{

If(type.compareTo(“Asian”)

return new AsianRace();

Else if(type.compareTo(“Scandinavian”)

return new ScandinavianRace();

Else if(type.compareTo(“African”)

return new AfricanRace();

}

}

The above code very staunchly suggests that HumanRace is an interface commonly implemented by all races.

Here is how we would use our classes to make a Human belonging to an African Race.

Human africanHuman = new HumanFactory();

africanHuman. InstatiateRace(“African”);

We have injected the dependency into the class Human from an outside class. We call this class the HumanFactory. We have also encapsulated all the changes that we foresee to this moment. In future if changes occur changing this class will result in less conflicts in our project, then changes in the main class. Further for example if a new race is found , we would make a new class that implements the HumanRace Interface and add it in the HumanFactory. It’s simple enough. The main class doesn’t and shouldn’t know what race it is working on. This is neat. We can be rest assured if we follow this design that our code won’t break in face of this modification , and our changes would be gracefully adjusted into the system.

There is still a hassle though. You still would to open up your code and add

Human newHuman = new HumanFactory();

newHuman. InstatiateRace(“newRace”);

But this is very minimal of work, and the advantage we have here is that we know nothing would break up. Just adding this one line that we know would safely work is billion times better than adding many lines in the main class code that WE ARE NOT sure would safely work.

Issues with the Factory

Okay lets be honest , as mentioned in the closing statements of the above material; we DO need to add some modification to the code in order to use a new implementation. Now this is fine for the above case ; but if we stretch the domain of this application then we’ll have to make a lot of such statements if a new implementation has to be used. Plus there are other problems

1. The creation of an instance of an object is local to a factory. There is no way to alter the manner in which objects are created at run time. For example if to create class A , we need class B but this nature has changed such that we now need Class C for class A ; we would have to change the code by hand

2. We have said that we implemented the factory to encapsulate the changes in the main class. But we realize that now the factory itself faces the same problem. What if there are frequent changes required in the factory. We have hardcoded the instantiation of classes in the factory and we have made it non extensible. We have introduced extensibility and neatness in the main class, by making an inextensible dirty class.

3. Factories are custom to each individual implementation. For example, all the implementations above (AsianRace,AfricanRace) were for HumanRace. So we needed to make a factory for HumanRace’s implementation. This means for another implementation; we’d need another factory. So factories are custom and have to be made for each implementation

4. Interfaces decouple the construction of the object from the specific implementation of the interface. The dilemma that arises now is how you can accomplish this decoupling without being forced to create an interface for everything. ( from msdn).

Hmm okay so these were the problems that we’d face when we try to implement Dependency Injection using factories. There should be some superhero on rescue but we do notice that spidersenses or the ability of an individual to turn into a fireball won’t help.

DI Containers

Okay here is the best shot , the drug for the situation. Let us consider a box , in which we’d keep all our objects. Simple? . Up to this moment yes. So whatever objects my application is going to use , like objects for class Books,Student,Drama,College,DAO,Manager etc all these should be put into a box. We’d allow this box to manage all of our instantiation , whenever we need a reference to an object , we’ll dial 111-BOX , ask for the reference and satisfy our hunger with that. Object instantiation , creation, destruction, dependency check and other configurations should be handled by the box. From now on lets call the box the Container. The container should give us a ready to eat(use) object whenever one is needed. If there is a dependency then it should be resolved by the container before being handled out. For example

Class Student

{

Private String name;

Student(String name)

{

This.name=name;

NameValidator validator = new NameValidator(name)

}

}

There are two kinds of dependencies here. First is the obvious String in the constructor. Secondly this class is also dependent upon another class called NameValidator. Whenever I want to use a Student class , I’ll dial the Container and I expect that it would resolve all dependencies ( instantiate the NameValidator class etc) and return to me a object of the Student class.

Application of Spring in Frameworks

In Struts2 the objectFactory class is responsible for creating an object for an action. For example if the LoginAction should be instantiated , the ObjectFactory would create the instance for this class. However if we are using Spring, then the responsibility for object creation is deferred to the SpringFramework but allowing it to intervene in the Struts2 framework. This is achieved by downloading a plugin titled struts2-

spring-plugin-2.0.9.jar. This plugin provides a Spring extension of the core ObjectFactory. Spring has now the opportunity to create and manage any of the objects that until now ObjectFactory had been creating.


I hope you have a feel for Dependency Injections , just like you have it for a doctors one. Will write more on this again.



Thanks

No comments:

Post a Comment