• 依赖注入随写


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

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

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

       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框架也加入了这一层,它在带来简便性的同时也引入了复杂性,两层反射模式的使用必定会对性能带来损耗。所以,请时刻秉持简单易用的原则,谨慎的选择合适的方式来组织代码。

  • 相关阅读:
    设计模式学习笔记之状态模式
    设计模式学习笔记之观察者模式
    设计模式学习笔记之模板方法模式
    设计模式学习笔记之策略模式
    设计模式学习笔记之装饰者模式
    Comparable和Comparator接口的比较
    Java中关键字continue、break和return的区别
    斐波那契数列-兔子问题
    用Java编程计算猴子吃桃问题
    (转载)Java多线程入门理解
  • 原文地址:https://www.cnblogs.com/wangjieas/p/3415414.html
Copyright © 2020-2023  润新知