海水正蓝

面朝大海,春暖花开
posts - 145, comments - 29, trackbacks - 0, articles - 1
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

【转】依赖注入的简单实现

Posted on 2012-12-25 13:33 小胡子 阅读(235) 评论(0)  编辑  收藏 所属分类: 设计模式


Container注入框架的进入点

 1 namespace Skight.LightWeb.Domain
 2 {
 3     public class Container
 4     {
 5         private static Resolver underlying_resolver;
 6         public static Resolver Current
 7         {
 8             get { return underlying_resolver; }
 9         }
10         public static T get_a<T>()
11         {
12             return underlying_resolver.get_a<T>();
13         }
14 
15         public static void initialize_with(Resolver resolver)
16         {
17             underlying_resolver = resolver;
18         }
19     }
20 }

Container的实现核心,依赖解析器的接口定义。(接口名称,我不加I,故意的)


 1 using System;
 2 
 3 namespace Skight.LightWeb.Domain
 4 {
 5     public interface Resolver
 6     {
 7         Dependency get_a<Dependency>();
 8         object get_a(Type type);
 9     }
10 }

依赖解析器的测试 (使用Machine Specification)


 1 using System;
 2 using System.Collections.Generic;
 3 using Machine.Specifications;
 4 using Rhino.Mocks;
 5 
 6 namespace Skight.LightWeb.Domain.Specs
 7 {
 8     public class When_bind_a_class_to_a_intefercate
 9     {
10         private Establish context =
11             () =>
12                 {
13                     var item_resolver = MockRepository.GenerateMock<DiscreteItemResolver>();
14                     var dictioary = new Dictionary<Type, DiscreteItemResolver>();
15                     dictioary.Add(typeof (MockInterface), item_resolver);
16                     subject = new ResolverImpl(dictioary);
17                     item_resolver.Stub(x => x.resolve()).Return(new MockImplementaion());
18                 };
19 
20        private It should_resolve_the_interface_to_the_class =
21             () => subject.get_a<MockInterface>().ShouldBeOfType<MockImplementaion>();
22 
23         private static ResolverImpl subject;
24         private interface MockInterface { }
25         private class MockImplementaion : MockInterface { }
26         
27     }   
28 }

解构器的实现


 1 using System;
 2 using System.Collections.Generic;
 3 
 4 namespace Skight.LightWeb.Domain
 5 {
 6     public class ResolverImpl:Resolver
 7     {
 8         private readonly IDictionary<Type, DiscreteItemResolver> item_resolvers;
 9 
10         public ResolverImpl(IDictionary<Type, DiscreteItemResolver> itemResolvers)
11         {
12             item_resolvers = itemResolvers;
13         }
14 
15         public Dependency get_a<Dependency>()
16         {
17             return (Dependency) item_resolvers[typeof (Dependency)].resolve();
18         }
19 
20         public object get_a(Type type)
21         {
22             return item_resolvers[type].resolve();
23         }
24     }
25 }

注册器的接口定义 (是的,先要注册才能解析,可是业务视图却是反的)


1 namespace Skight.LightWeb.Domain
2 {
3     public interface Registration
4     {
5         void register<Contract, Implementaion>() where Implementaion : Contract;
6     }
7 }

注册器的的测试


 1 using System;
 2 using System.Collections.Generic;
 3 using Machine.Specifications;
 4 
 5 namespace Skight.LightWeb.Domain.Specs
 6 {
 7     public class When_use_Registration_to_register_an_infterface_to_a_class
 8     {
 9         private Establish context =
10             () =>
11                 {
12                     resolver_dictionary = new Dictionary<Type, DiscreteItemResolver>();
13                     subject = new RegistrationImpl(resolver_dictionary);
14                     
15             };
16 
17         private Because of =
18             () => subject.register<MockInterface, MockImplementation>();
19 
20         private It the_key_value_pair_should_be_added_to_resovler_dictionary =
21             () => resolver_dictionary[typeof (MockInterface)].resolve().ShouldBeOfType<MockImplementation>();
22         
23         private static RegistrationImpl subject;
24         private static Dictionary<Type, DiscreteItemResolver> resolver_dictionary;
25 
26         private interface MockInterface{}
27         private class MockImplementation:MockInterface {}
28     }
29 }

注册器的的实现

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 namespace Skight.LightWeb.Domain
 5 {
 6     public class RegistrationImpl:Registration
 7     {
 8         private IDictionary<Type, DiscreteItemResolver> item_resolvers;
 9         public RegistrationImpl(IDictionary<Type, DiscreteItemResolver> item_resolvers)
10         {
11             this.item_resolvers = item_resolvers;
12         }
13 
14         public void register<Contract, Implementation>() where Implementation : Contract
15         {
16            
17             item_resolvers.Add(typeof(Contract), new TypeResolver(typeof(Implementation)));
18         }
19     }
20 
21 }

具体解构器接口定义 (命名:离散解构器,可以看作是对象工厂的一种形式)


1 namespace Skight.LightWeb.Domain
2 {
3     public interface DiscreteItemResolver
4     {
5         object resolve();
6     }
7 }

离散解构器的测试


 1 using System;
 2 using Machine.Specifications;
 3 using Rhino.Mocks;
 4 
 5 namespace Skight.LightWeb.Domain.Specs
 6 {
 7     public class TypeResolverSpecs
 8     {
 9         protected static TypeResolver subject;
10     }
11 
12     public class given_a_simple_type_which_has_a_parameterless_constructor
13         : TypeResolverSpecs
14     {
15         private Establish context =
16             () => subject = new TypeResolver(typeof (SimpleType));
17 
18         private It should_create_object_from_class =
19             () => subject.resolve().ShouldBeOfType<SimpleType>();
20 
21         protected class SimpleType{}
22     }
23 
24     public class given_a_complex_type_whose_constructor_need_other_types
25        : TypeResolverSpecs {
26         private Establish context =
27             () =>
28                 {
29                     var resolver = MockRepository.GenerateMock<Resolver>();
30                     Container.initialize_with(resolver);
31                     resolver.Stub(x => x.get_a(Arg<Type>.Is.Equal(typeof (SimpleType))))
32                         .Return(new SimpleType());
33 
34                     subject = new TypeResolver(typeof (ComplexType));
35             };
36 
37         private It should_create_object_from_class =
38             () => subject.resolve().ShouldBeOfType<ComplexType>();
39 
40         protected class SimpleType{}
41         protected class ComplexType
42         {
43             private SimpleType simple;
44 
45             public ComplexType(SimpleType simple)
46             {
47                 this.simple = simple;
48             }
49         }
50     }
51 }

离散解构器的实现 (有递归,如果该类构造器有接口参数的,需要用Container解构)


 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Reflection;
 5 
 6 namespace Skight.LightWeb.Domain
 7 {
 8     public class TypeResolver:DiscreteItemResolver
 9     {
10         private readonly Type type_to_create;
11 
12         public TypeResolver(Type type_to_create)
13         {
14             this.type_to_create = type_to_create;
15         }
16 
17         public object resolve()
18         {
19             ParameterInfo[] param_types = get_constructor_parameters();
20             IEnumerable<object> parameters = get_parameters(param_types);
21             return Activator.CreateInstance(type_to_create, parameters.ToArray());
22         }
23 
24         private IEnumerable<object> get_parameters(ParameterInfo[] param_types)
25         {
26             return param_types.Select(x => Container.Current.get_a(x.ParameterType));
27         }
28 
29         private ParameterInfo[] get_constructor_parameters()
30         {
31             var constructor= type_to_create.GetConstructors()
32                 .OrderByDescending(x => x.GetParameters().Count())
33                 .First();
34             return constructor.GetParameters();
35         }
36     }
37 }

集成测试,完整的用例。


 1 using System;
 2 using System.Collections.Generic;
 3 using Machine.Specifications;
 4 
 5 namespace Skight.LightWeb.Domain.Specs
 6 {
 7     public class DependencyIntegrationSpecs
 8     {
 9         private Establish context =
10             () =>
11                 {
12                     IDictionary<Type, DiscreteItemResolver> item_resolvers = new Dictionary<Type, DiscreteItemResolver>();
13                     registration = new RegistrationImpl(item_resolvers);
14                     Container.initialize_with(new ResolverImpl(item_resolvers));
15                     
16                 };
17 
18         protected static Registration registration;
19     }
20 
21     public class when_registry_a_simple_class_RepositoryImpl_without_further_dependency:DependencyIntegrationSpecs
22     {
23         private Establish context =
24             () => registration.register<Repository, RepositoryImpl>();
25         private Because of =
26            () => result = Container.get_a<Repository>();
27 
28         private It should_get_a_object_which_is_not_null =
29             () => result.ShouldNotBeNull();
30 
31         private It should_get_RepositoryImpl_class =
32             () => result.ShouldBeOfType<RepositoryImpl>();
33 
34         private static Repository result;
35     }
36 
37     public class when_registry_a_class_ServiceImpl_which_depend_on_another_interface_Repository : DependencyIntegrationSpecs {
38         private Establish context =
39             () => {
40                 registration.register<Repository, RepositoryImpl>();
41                 registration.register<Service,ServiceImpl>();
42             };
43         private Because of =
44            () => result = Container.get_a<Service>();
45 
46         private It inject_repository_should_not_be_null =
47             () => result.ShouldNotBeNull();
48 
49         private It should_inject_service =
50             () => result.ShouldBeOfType<ServiceImpl>();
51 
52         private It should_inject_repository_into_service =
53             () => result.Repository.ShouldBeOfType<RepositoryImpl>();
54         
55 
56         private static Service result;
57     }
58     public interface Repository { }
59     public class RepositoryImpl : Repository { }
60     public interface Service{Repository Repository { get; } }
61     public class ServiceImpl : Service
62     {
63         private Repository repository;
64 
65         public ServiceImpl(Repository repository)
66         {
67             this.repository = repository;
68         }
69 
70         public Repository Repository
71         {
72             get { return repository; }
73         }
74     }
75 }

Bootstrapper系鞋带代码,把所有的碎片组合起来,作为Web,在Gloable.asax中调用


 1 using System;
 2 using System.Collections.Generic;
 3 using Skight.LightWeb.Domain;
 4 using Skight.LightWeb.Presentation.Web.FrontController;
 5 
 6 
 7 namespace Skight.LightWeb.Application.Startup
 8 {
 9     public class ApplicationStartup
10     {
11         public void run()
12         {
13             IDictionary<Type, DiscreteItemResolver> item_resolvers = new Dictionary<Type, DiscreteItemResolver>();
14             Container.initialize_with(new ResolverImpl(item_resolvers));
15             var registration = new RegistrationImpl(item_resolvers);
16             registration.register<Repository,RepositoryImpl>();
17             registration.register<FrontController,FrontControllerImpl>();
18             registration.register<CommandResolver,CommandResolverImpl>();
19             
20         }
21 
22         /// <summary>
23         /// Test purpose class an interface
24         /// </summary>
25         public interface Repository { }
26         public class RepositoryImpl : Repository { }
27     }
28 }

原文出自:
http://www.oschina.net/code/snippet_871522_15682







只有注册用户登录后才能发表评论。


网站导航: