Software Craftsmanship : Implement Inversion of Control with Dependency Injection & Service locator
来源:互联网 发布:智能锁屏软件 编辑:程序博客网 时间:2024/06/10 20:38
/*
Author: Jiangong SUN
*/
Last update : 11/09/2013
What is Inversion of Control ?
The object of IoC is to eliminate the code coupling.
The ideas of IoC are:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend upon details. Details should depend upon abstractions.
What is dependency Injection ?
DI is a form of IoC, where implementations are passed into an object through constructors/setters/service look-ups, which the object will 'depend' on in order to behave correctly.
Do not instantiate the dependencies explicitly in your class. Instead, declaratively express dependencies in your class definition. Use a Builder object to obtain valid instances of your object's dependencies and pass them to your object during the object's creation and/or initialization.
Typically, you express dependencies on interfaces instead of concrete classes. This enables easy replacement of the dependency concrete implementation without modifying your classes' source code.
There are some ways of implementing Dependency Injection.
- Constructor Injection
- Setter Injection
- Interface based Injection
- Service locator Injection
- Generic Injection
In constructor injection, you use parameters of the object's constructor method to express dependencies and to have the builder inject it with its dependencies.
In setter injection, the dependencies are expressed through setter properties that the builder uses to pass the dependencies to it during object initialization.
Dependency Injection Tools ?
Spring.NET, Ninject, Windsor
Here I will create a code sample who is tightly coupled.
public class Customer { private Address _address; public Customer() { _address = new Address(); } public void GetAddress() { Console.WriteLine("{0}, {1}, {2}, {3}", _address.Name, _address.Road, _address.City, _address.Country); } } public class Address { public string Name { get; set; } public string Road { get; set; } public string City { get; set; } public string Country { get; set; } }If "Address" class has different subclasses who inherit from it, and we need to call them in Customer class, we have to add instance of different subclasses and potentially modify "GetAddress" method.
public class FacturationAddress : Address { public string FacturationName { get; set; } public void GetAddress() { Console.WriteLine("FacturationName: {0}, {1}, {2}, {3}, {4}", FacturationName, Name, Road, City, Country); } } public class DeliveryAddress : Address { public string DeliveryName { get; set; } public void GetAddress() { Console.WriteLine("DeliveryName: {0}, {1}, {2}, {3}, {4}", DeliveryName, Name, Road, City, Country); } }
With the above code, I think I should totally rewrite the "Customer" class. For example, I can add instances of "FacturationAddress" and "DeliveryAddress" to meet the requirement. But if there will be more subclasses in the future, I have to re-modify the "Customer" class which is not recommended.
As Inversion of Control indicates, the higher level modules should not depend on lower high modules, and they need to depend on abstractions. And abstractions should not depend details, details should depend on abstractions.
This means, "Customer" and "Address" should depend on abstractions, and the implementations of Addresses' methods should be transparent to the "Customers".
Firstly, I will introduce to you an example of Constructor Injection to solve the problem.
I will create an interface who declares some properties and method, the classes who implement it will declare the implementation of declared method .
public interface IAddress { string Name { get; set; } string Road { get; set; } string City { get; set; } string Country { get; set; } string GetAddress(); } public class FacturationAddress : IAddress { public string FacturationName { get; set; } public string Name { get; set; } public string Road { get; set; } public string City { get; set; } public string Country { get; set; } public string GetAddress() { return string.Format("Facturation Address: {0},{1},{2},{3},{4}", FacturationName, Name, Road, City, Country); } } public class DeliveryAddress : IAddress { public string DeliveryName { get; set; } public string Name { get; set; } public string Road { get; set; } public string City { get; set; } public string Country { get; set; } public string GetAddress() { return string.Format("Delivery Address: {0},{1},{2},{3},{4}", DeliveryName, Name, Road, City, Country); } }
Then in Customer class, create a local Address interface variable and assign an object in class constructor. And then, use a method to call the local variable's method.
public class Customer { private IAddress _address; public Customer(IAddress address) { _address = address; } public string GetAddress() { return _address.GetAddress(); } }
To test with fake data, we can see that it works perfectly. And when I need to add new classes, I don't need to modify Customer class.
FacturationAddress facturationAddress = new FacturationAddress() { FacturationName = "Charles sun", City = "paris", Country = "France", Name = "charles", Road = "haussman" }; Customer customer = new Customer(facturationAddress); Console.WriteLine(customer.GetAddress()); DeliveryAddress deliveryAddress = new DeliveryAddress() { DeliveryName = "jiangong", City = "Paris", Country = "France", Name = "charles", Road = "12 avenue champs élysée" }; Customer customer2 = new Customer(deliveryAddress); Console.WriteLine(customer2.GetAddress());
But there is a limitation which is I need to pass an object to the class constructor, which may cause problems.
Then I will present Setter Injection to solve the same problem.
I will create the same IAddress interface, FacturationAddress and DeliveryAddress as the previous solution.
But the Customer class will change.
public class Customer { private IAddress _address { get; set; } public IAddress Address { get { return _address; } set { _address = value; } } public string GetAddress() { return _address.GetAddress(); } }In this version, I don't need to pass an object in the class constructor. I just need to instanciate the Address instance of IAddress.
Customer customer = new Customer(); FacturationAddress facturationAddress = new FacturationAddress() { FacturationName = "Charles sun", City = "paris", Country = "France", Name = "charles", Road = "haussman" }; customer.Address = facturationAddress; //setter Console.WriteLine(customer.GetAddress()); DeliveryAddress deliveryAddress = new DeliveryAddress() { DeliveryName = "jiangong", City = "Paris", Country = "France", Name = "charles", Road = "12 avenue champs élysée" }; customer.Address = deliveryAddress; //setter Console.WriteLine(customer.GetAddress());In this way, the problem is solved too.
Service Locator is another way to implement Inversion of Control.
I will present how to solve the same problem with Service Locator.
public class ServiceLocator { //public ServiceLocator() { } private IAddress _Address; public IAddress GetService(IAddress address) { if (_Address == null) { _Address = address; } return _Address; } }
With Customer class, it just need to call the method of service locator.
public class Customer { private IAddress _address { get; set; } public Customer(IAddress address) { _address = new ServiceLocator().GetService(address); } public string GetAddress() { return _address.GetAddress(); } }
In this way, in case of addtion of new classes, Customer class doesn't need to be modified.
FacturationAddress facturationAddress = new FacturationAddress() { FacturationName = "Charles sun", City = "paris", Country = "France", Name = "charles", Road = "haussman" }; Customer customer = new Customer(facturationAddress); Console.WriteLine(customer.GetAddress()); DeliveryAddress deliveryAddress = new DeliveryAddress() { DeliveryName = "jiangong", City = "Paris", Country = "France", Name = "charles", Road = "12 avenue champs élysée" }; Customer customer2 = new Customer(deliveryAddress); Console.WriteLine(customer2.GetAddress());
Reference:
http://www.codeproject.com/Articles/29271/Design-pattern-Inversion-of-control-and-Dependency
http://www.codeproject.com/Articles/380748/Inversion-of-Control-Overview-with-Examples
http://www.codeproject.com/Articles/592372/Dependency-Injection-DI-vs-Inversion-of-Control-IO
http://www.codeproject.com/Articles/465173/Dependency-Inversion-Principle-IoC-Container-and-D
http://www.codeproject.com/Articles/31210/Model-View-Presenter
http://msdn.microsoft.com/en-us/library/ff921087(v=pandp.20).aspx
http://www.codeproject.com/Articles/13831/Dependency-Injection-for-Loose-Coupling
http://stackoverflow.com/questions/6550700/inversion-of-control-vs-dependency-injection
http://www.dotnet-tricks.com/Tutorial/dependencyinjection/bSVa100413-Understanding-Inversion-of-Control,-Dependency-Injection-and-Service-Locator.html
http://stackoverflow.com/questions/1710005/abstractions-should-not-depend-upon-details-details-should-depend-upon-abstract
http://www.springframework.net/doc-latest/reference/html/introduction.html#introduction-overview
- Software Craftsmanship : Implement Inversion of Control with Dependency Injection & Service locator
- 依赖注入 控制反转 服务定位器 模式 Dependency Injection Inversion of Control Service Locator Patterns | 超级经典
- 依赖注入 控制反转 服务定位器 模式 Dependency Injection Inversion of Control Service Locator Patterns | 超级经典
- Inversion of Control and Dependency Injection with Castle Windsor Container
- 解析Inversion of control和Dependency Injection
- Inversion of Control (IoC) and Dependency Injection
- Inversion of control and Dependency injection
- IOC-Inversion of Control, Dependency Injection
- IOC(DI)- Inversion of Control(Dependency Injection)
- Dependency injection and inversion of control
- IoC,Dependency Injection,Service Locator
- Dependency Injection 和 Service Locator
- Inversion of Control and Dependency Injection with Castle Windsor Container - Part I
- Inversion of Control/Dependency Injection with Repository Pattern, Fluent Nhibernate, and LightCore
- Inversion of Control Containers and the Dependency Injection pattern
- Inversion of Control Containers and the Dependency Injection pattern
- Inversion of Control Containers and the Dependency Injection pattern
- Inversion of Control Containers and the Dependency Injection pattern
- 通过CTS学习Android API系列1——CTS结果分析及用例研究
- Jquery让图片根据浏览器窗口大小自动缩放
- android 创建socket 通信型service
- C# dateGRIDVIEW导出EXCEL文件
- JS中截图工具:copper
- Software Craftsmanship : Implement Inversion of Control with Dependency Injection & Service locator
- 在C++中用C#风格设置类的属性值
- No matching function call to 'pthread_create'
- 做一个正气的杭电人
- mysql 远程登录权限设置
- 游戏开发工具之纹理打包器-1.创建界面及连接控件.
- [转]keybd_event 被 SendInput 替代
- Unity 3D 获取手机SD卡目录列表
- How can I always run the command prompt as administrator?