海水正藍

          面朝大海,春暖花開
          posts - 145, comments - 29, trackbacks - 0, articles - 1
            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

          【轉】依賴注入的簡單實現

          Posted on 2012-12-25 13:33 小胡子 閱讀(244) 評論(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






          主站蜘蛛池模板: 昌江| 墨玉县| 安阳市| 南投市| 肇州县| 鄯善县| 宝鸡市| 昌邑市| 莱阳市| 武隆县| 沂水县| 赣州市| 龙泉市| 瑞昌市| 太康县| 安远县| 扎赉特旗| 沙雅县| 来凤县| 章丘市| 桃园县| 江川县| 宁乡县| 巴里| 南京市| 酉阳| 象山县| 华阴市| 上饶市| 丘北县| 三门峡市| 华亭县| 九江市| 汉寿县| 上思县| 屏东县| 丰宁| 息烽县| 延津县| 淮南市| 西乌珠穆沁旗|