This entry shows from an easy point of view the Unity 2.0 functionality and the main concepts and components related to it.
My goal is to convey the concepts as though we were on the street talking about the weather or so.
There are three functionalities Unity 2.0 provides by implementing the following design patterns:
1) Dependency Injection pattern. Basically, this pattern can be used when you need to create class instances without assigning memory explicitly.
2) Inversion of control pattern. This pattern decouples how the class instances are created. That is to say,
3) Interception pattern. Basically, this pattern permits to implement additional functionality in runtime.
4) Factory pattern. This
pattern has the goal of providing object instances and manage how this
instances are created.
Unity 2.0 provides the following functionality in order to implement design patterns properly and give the software architecture a good design approach.
The following example implements a Factory
Class which provides the instances requested by the code. This factory
class implements the Factory Pattern, and therefore it decouples the mechanism
of instance creation from the application code.
The Factory class implementation is
based on Unity Container. Unity Container manages the dependencies between the
set of objects that takes part of the application efinition. As you may know,
objects have dependencies with other objects.
That is to say, a class called GreetingFormal have a constructor
that exposes a parameter of a specific type (for instance, GreetingLanguageSpanish).
When a GreetingFormal object is created,
Unity container injects a new instance of the specific type (GreetingLanguageSpanish)
to the constructor and therefore the
parameter gets a new value or reference. This injection is made by the container. Since
that Unity Container manages the relationship creation among the objects, the
application source code is out of this responsibility and therefore decoupling
instantiation processes from the application is a fact.
Finally, as you can see, application
does not need to be concerned about how to establish all dependencies. In
addition, application does not need to assign a specific instance of a specific
type to a specific application variable. Instead, it is Unity Container the
responsible of providing the current instance of a specific type. That is
called Inversion of control. It is call inversion of control because it is the
container who manages the instance creation instead of being the application by
using the “new” instruction.
With all this stuff described,
indeed there is a main goal that justifies all these pattern considerations. Decoupling the instance management from the
application.
This example shows how you can
implement these three patterns by using Unity 2.0
Firstly, Here you are the factory
(be aware that the code style could be improved, but the goal of this entry is
to show how to implement the patterns based on Unity implementation).
The factory class is the following.
public
static class FactoryProvider
{
private
static IUnityContainer
container;
public static Object getInstance(Type
type,string name)
{
if
(container == null)
{
container = new UnityContainer();
container.LoadConfiguration();
Object
obj = container.Resolve(type,name);
return
obj;
}
else
{
Object
obj = (Object)container.Resolve(type, name);
return
obj;
}
}
}
This class is the implementation of the so-called
Factory Pattern, and encapsulates all object creation implementations.
Application has only to use the static Factory class by
invocating the method getInstace in order to get a new instance.
IGreeting os= (IGreeting)FactoryProvider.getInstance(typeof(IGreeting),
"greetingSpanish");
The container is in charge of establishing all
dependencies when they are required. Therefore, unity container is the responsible
of instancing all dependences among objects. The main application does not know
anything about this issue. It just uses instances by requesting them to the
Factory class.
In order to define the dependencies between objects,
Unity provides two mechanisms to get it. In this example I use the common Unity
section included within the app.config file.
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<!--
unity section-->
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<namespace name="GreetingClient" />
<assembly name="GreetingClient" />
<alias alias="IGreetingLanguage" type="IGreetingLanguage,
GreetingLanguageEnglish" />
<container>
<!--
Type instance. This is a instance of the GreetingLanguageEnglish type.-->
<!--<instance
name="lenglish" type
="IGreetingLanguage"
typeConverter="GreetingTypeConverter"/>-->
<register type="IGreetingLanguage" name="lenglish" mapTo="GreetingLanguageEnglish">
<lifetime type="singleton"/>
<method name="establishLanguage">
<param name="language">
<value value="slang"/>
</param>
</method>
</register>
<register type="IGreetingLanguage" name="lspanish" mapTo="GreetingLanguageSpanish">
<lifetime type="singleton"/>
<method name="establishLanguage">
<param name="language">
<value value="formal"/>
</param>
</method>
</register>
<!--
This is a registered GreetingFormal
object whose constructor accept a IGreetingLanguage parameter-->
<register type="IGreeting" name="greetingEnglish" mapTo="GreetingFormal">
<constructor>
<param dependencyName="lenglish" name="language" type="IGreetingLanguage"/>
</constructor>
</register>
<register type="IGreeting" name="greetingSpanish" mapTo="GreetingFormal">
<constructor>
<param dependencyName="lspanish" name="language" type="IGreetingLanguage"/>
</constructor>
</register>
</container>
</unity>
</configuration>
Several remarks about the unity section.
Firstly, I would like to explain the example in order
to understand better the xml definition.
This example is very simple.
There is a class called GreetingFormal that implements
the IGreeting interface. The class has a method called “greeting” that print a
greeting message. This message can be an English message or a Spanish message,
depend on the class implementing IGreetingLanguage it uses. Class constructor
accepts an IGreetingLanguage-implemented class as constructor argument. The
Unity container established all injections which are defined within the Unity
section of the app.config file.
<register type="IGreeting" name="greetingEnglish" mapTo="GreetingFormal">
<constructor>
<param dependencyName="lenglish" name="language" type="IGreetingLanguage"/>
</constructor>
</register>
Each GreetingLanguage classes can be configured
to decide which the language usage is: formal or informal.
<register type="IGreetingLanguage" name="lenglish" mapTo="GreetingLanguageEnglish">
<lifetime type="singleton"/>
<method name="establishLanguage">
<param name="language">
<value value="slang"/>
</param>
</method>
</register>
This file, as a conclusion, defines the dependencies
among objects. Unity container instantiates all references and relationships.
container
= new UnityContainer();
container.LoadConfiguration();
Now is the turn of the Inversion of control.
Application uses the Factory class to obtain a specific instance of an object. It
is not the application which instantiates (new keyword). It is the container
wrapped by the Factory class which does.
Application have only to use the Factory method (getInstance
) to obtain the current one.
IGreeting os= (IGreeting)FactoryProvider.getInstance(typeof(IGreeting),
"greetingSpanish");
The
following code list shows each component of this example.
Factory
class that shows how the factory pattern is:
public
static class FactoryProvider
{
private
static IUnityContainer
container;
public static Object getInstance(Type
type,string name)
{
if (container == null)
{
container = new UnityContainer();
container.LoadConfiguration();
Object
obj = container.Resolve(type,name);
return
obj;
}
else
{
Object
obj = (Object)container.Resolve(type, name);
return obj;
}
}
}
With regard to Language features, here there is the code.This is the interface implementing the language
classes.
public
interface IGreetingLanguage
{
string
getMessage();
}
And these are the language classes.
public
class GreetingLanguageEnglish
: IGreetingLanguage
{
private
string message;
public void establishLanguage(string
language)
{
if
(language.CompareTo("formal") ==
0)
{
message = "Dear ";
}
else
{
message="Hi ";
}
}
string IGreetingLanguage.getMessage()
{
return
message;
}
}
public
class GreetingLanguageSpanish:IGreetingLanguage
{
private
string message;
public void establishLanguage(string language)
{
if
(language.CompareTo("formal") ==
0)
{
message = "Estimado ";
}
else
{
message = "Hola ";
}
}
string
getMessage()
{
return message;
}
}
This is the class that manages the Greetings.
public
interface IGreeting
{
string
greeting(string name);
}
public class GreetingFormal : IGreeting
{
private
string greetingMessage;
public
GreetingFormal(IGreetingLanguage language)
{
greetingMessage =
language.getMessage();
}
#region IGreeting
Members
public virtual string greeting(string
name)
{
return
greetingMessage + " " + name;
}
#endregion
#region IGreeting
Members
#endregion
}
Finally, the console application instanciates the GreetingFormal
class without knowing how the dependency injection is conformed and delegating
the instantiation process to the Unity Container.
static
void Main(string[]
args)
{
Console.WriteLine("Start");
IGreeting
os= (IGreeting)FactoryProvider.getInstance(typeof(IGreeting),
"greetingSpanish");
IGreeting
oe = (IGreeting)FactoryProvider.getInstance(typeof(IGreeting),
"greetingEnglish");
Console.WriteLine
(os.greeting("Fernando"));
Console.WriteLine(oe.greeting("Ferdinand"));
Console.WriteLine("Finish");
}
The console result is the following:
No comments:
Post a Comment