依赖注入随写

    遵循接口分离原则是编写健壮可扩展程序的基本要求。软件的复杂性使用不断增加新层的方式解决,而层之间的耦合则依赖接口隔离的方式解决。

  工厂模式是接口子类化的经典模式,工厂模式的实现方式,以前的随笔中已经详述过,故略去。这种子类化是一种主动式的子类化方法,调用者主动在需要的时候,进行子类化。而依赖注入模式则是一种被动式的子类化,其接口的子类化由调动者的调用者完成,如名字所述,其子类化的方式依靠反射功能实现注入,具体来分,又分为初始注入和属性赋值注入两种方式。在两种注入模式中,初始注入模式仅调用一次反射完成注入。

  下面是一个简单的依赖注入框架:

   1.子类化接口与初始注入接口类:

 1     public interface IDependency {
 2         Object GetService(Type type);
 3     }
 4 
 5     public class DefaultDependency : IDependency {
 6         public object GetService(Type type) {
 7             if (type.GetConstructor(Type.EmptyTypes) != null) {
 8                 return Activator.CreateInstance(type);
 9             }
10 
11             try {
12                 //just use the first constructor
13                 var cons = type.GetConstructors()[0];
14                 var paras = cons.GetParameters();
15                 var objs = new Object[paras.Length];
16                 for (int i = 0; i < paras.Length; i++) {
17                     objs[i] = InstanceMap.CreateInstance(paras[i].ParameterType);
18                 }
19                 return cons.Invoke(objs);
20             } catch(Exception ex){
21                 throw new InstanceInitException(ex);
22             }
23         }
24     }

2.初始参数仓库

  1     public static class InstanceMap {
  2         public static Object CreateInstance(Type type) {
  3             foreach (var unit in units) {
  4                 if (unit.InterfaceType == type) {
  5                     return unit.CreateInstance();
  6                 }
  7             }
  8             return null;
  9         }
 10 
 11         public static void Config(Action<InstanceSetting> customConfig) {
 12             customConfig(innerSetting);
 13         }
 14 
 15         public static InstanceUnit For<InterfaceType>() {
 16             return For(typeof(InterfaceType));
 17         }
 18 
 19         public static InstanceUnit For(Type interfaceType) {
 20             foreach (var un in units) {
 21                 if (un.InterfaceType == interfaceType) return un;
 22             }
 23 
 24             var unit = new InstanceUnit();
 25             unit.InterfaceType = interfaceType;
 26 
 27             units.AddLast(unit);
 28             return unit;
 29         }
 30 
 31         static LinkedList<InstanceUnit> units = new LinkedList<InstanceUnit>();
 32         static InstanceSetting innerSetting = new InstanceSetting();
 33     }
 34 
 35     public class InstanceUnit{
 36         internal InstanceUnit() {
 37             useSingleMode = false;
 38         }
 39 
 40         public Object CreateInstance() {
 41             if (useSingleMode) {
 42                 if (singleInstance == null) {
 43                     if (instanceType == null) return null;
 44                     singleInstance = createInstance(instanceType, parameters);
 45                 }
 46                 return singleInstance;
 47             } else {
 48                 if (instanceType == null) return null;
 49                 else return createInstance(instanceType,parameters);
 50             }
 51         }
 52 
 53         public Type InterfaceType { get; set; }
 54 
 55         Object[] parameters { get; set; }
 56         Type instanceType { get; set; }
 57         Boolean useSingleMode { get; set; }
 58         Object singleInstance { get; set; }
 59 
 60         public InstanceUnit Reflect<InstanceType>() {
 61             return Reflect(typeof(InstanceType));
 62         }
 63         public InstanceUnit Reflect(Type type) {
 64             instanceType = type;
 65             return this;
 66         }
 67 
 68         public InstanceUnit ReflectSingle(Object singleInstance) {
 69             useSingleMode = true;
 70             singleInstance = singleInstance;
 71             return this;
 72         }
 73         public InstanceUnit ReflectSingle<InstanceType>() {
 74             useSingleMode = true;
 75             this.instanceType = typeof(InstanceType);
 76             return this;
 77         }
 78 
 79         public InstanceUnit Paras(params Object[] objs) {
 80             parameters = objs;
 81             return this;
 82         }
 83 
 84         static Object createInstance(Type type, Object[] paras) {
 85             var paraTypes = new Type[paras.Length];
 86 
 87             var i = 0;
 88             Array.ForEach(paras, value => {
 89                 paraTypes[i] = value.GetType();
 90                 i++;
 91             });
 92 
 93             var constructor = type.GetConstructor(paraTypes);
 94             try {
 95                 return constructor.Invoke(paras);
 96             } catch {
 97                 return null;
 98             }
 99         }
100     }
101 
102     //for test
103     public class InstanceSetting {
104         public void AutoScanRegistedInstance() { }
105         public void AllowScanAllAssemblies(){}
106     }

3.使用方式

 1     class Program {
 2         static void Main(string[] args) {
 3 
 4             InstanceMap.Config(cfg => {
 5                 cfg.AllowScanAllAssemblies();
 6             });
 7             InstanceMap.For<ITemp>().ReflectSingle<Temp>().Paras("wangjieas");
 8             ((new DefaultDependency()).GetService(typeof(TempUser)) as TempUser).Say();
 9 
10             Console.Read();
11         }
12     }
13 
14     public interface IMessage {
15         String Message { get; }
16     }
17 
18     public class Message : IMessage {
19         public Message(String str) {
20             innerString = str;
21         }
22 
23         string IMessage.Message {
24             get { return innerString; }
25         }
26 
27         String innerString;
28     }
29 
30     public interface ITemp {
31         String Message { get; }
32     }
33 
34     public class Temp : ITemp {
35         public Temp(String name) {
36             this.name = name;
37         }
38 
39         public string Message {
40             get { return String.Format("Hello,{0}", name); }
41         }
42 
43         String name;
44     }
45 
46 
47     public class TempUser {
48         public TempUser(ITemp temp) {
49             this.temp = temp;
50         }
51 
52         public void Say() {
53             Console.WriteLine(temp.Message);
54         }
55 
56         ITemp temp;
57     }

  后记1:上面是一个简单的实现,仅仅用于测试。有兴趣的话,可以继续扩展。比如InstanceUnit中的Para,可以单独出来,分别对应配置文件项目和类attr值。DI经典的使用方式,自动化测试与mvc模式。

      后记2:DI是spring框架的拿手好戏,最新的asp.net mvc框架也加入了这一层,它在带来简便性的同时也引入了复杂性,两层反射模式的使用必定会对性能带来损耗。所以,请时刻秉持简单易用的原则,谨慎的选择合适的方式来组织代码。

posted on 2013-11-09 11:01  wangjieas  阅读(1129)  评论(0编辑  收藏  举报

导航