微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

依赖倒置DIP与依赖注入DI

  依赖倒置原则(Dependency Inversion Principle)为我们提供了降低模块间耦合度的一种思路,依赖注入(Dependency Injection)是一种具体的实施方法

依赖倒置原则:

  “依赖倒置原则”(Dependency Inversion Principle),该原则主要是为了降低模块与模块之间的“耦合度”,提倡模块与模块之间不要发生直接的依赖关系,即:高层模块不应该直接依赖于低层模块,高层模块和低层模块应该同时依赖一个抽象层。如果现在有一个类Manager在处理某一任务时,需要记录错误日志,那么我们可以这样编写代码

复制代码

 1 class Manager
 2 {
 3     //
 4     FileLogger _logger;
 5     public void DoSomething()
 6     {
 7         try
 8         {
 9             …do something
10         }
11         catch(Exception ex)
12 13             if(_logger == null)
14             {
15                 _logger = new FileLogger();
16             }
17             _logger.Log(ex.ToString())
18 19     }
20 }
21  FileLogger
22 23     void Log(string errorLog)
24 25         …write into log file
26 27 }

复制代码

如上代码所示,FileLogger类负责将错误日志保存到文件,Manager类中定义了一个Logger类对象,专门负责记录错误日志,这段代码中的“高层模块”Manager类就直接依赖与“低层模块”FileLogger,如果我们现在需要将错误日志记录通过Email发送给别人,或者发送给别的模块,我们不得不去修改Manager类的代码

  “依赖倒置原则”建议我们,Manager类不应该直接依赖于FIleLogger类,而应该依赖一个抽象层(接口层),所以原来代码应该这样写:

3 ILog _logger; 4 5 6 7 8 9 10 11 12 13 14 _logger = 15 _logger = new EmailLogger(); 16 _logger = new NotifyLogger(); _logger.Log(ex.ToString()); interface ILog 23 24 errorLog); 25 FileLogger:ILog 27 28 29 30 …write into file 31 32 33 EmailLogger:ILog 34 35 36 37 …send to others as email 38 39 40 NotifyLogger:ILog 41 42 43 44 … notify other modules 45 46 }
如上代码所示,我们把记录错误日志的逻辑抽象出来一个ILog接口,Manager类不再依赖于任何一个具体的类,而是依赖于ILog接口,同时我们可以根据ILog接口实现各种各样的日志记录类,如FileLogger将日志保存到文件、EmailLogger将日志以邮件形式发送给别人、NotifyLogger将错误信息通知程序中其他模块。这样以来,整个代码的灵活度明显增加了,如果我们需要将日志保存到文件,直接使用FileLogger,如果我们想将日志以邮件形式发送别人,直接使用EmailLogger等等。下图显示依赖倒置发生前后:

 

依赖注入:

  上面的Manager类虽然不再直接依赖任何具体的日志记录类型,但是实质上,我们创建记录日志类对象还是在Manager内部(catch中),如果我们想换种方式记录日志,还是得动Manager类的代码,有没有一种方式,能够让我们不需要修改Manager代码就能切换日志的记录方式呢?当然是有的,“依赖注入”就是这一问题的具体解决方法,我们有三种方式去让两个类型发生依赖关系:

(1)构造注入(Constructor Injection)

  在我们创建Manager对象的时候,将记录日志的对象作为构造参数传递给新创建的Manager对象,假设Manager有一个带ILog类型参数的构造方法,如:

1 2 3 4 public Manager(ILog logger) 5 6 _logger = logger; 7 8 9 }
那么,我们在创建Manager对象的时候,这样编写代码

  Manager m = new Manager(new FileLogger());

  //Manager m = new Manager(new EmailLogger());

  //Manager m = new Manager(new NotifyLogger());

很明显,这种日志记录方式一直不变,对Manager终生有效。

(2)方法注入(Method Injection)

  为Manager类中每个需要记录日志的方法增加一个ILog的参数,比如Manager.DoSomething方法重新定义为:

DoSomething(ILog logger) 8 logger.Log(ex.ToString()); 15 }
那么我们之后在使用Manager的时候,每次调用方法都应该为它提供一个记录日志的对象,如:

  Manager m = new Manager();

  m.DoSomething(new FileLogger());

  m.DoSomething(new EmailLogger());

  m.DoSomething(new NotifyLogger());

这种记录日志的方式,只对当前方法有效,每次调用方法都可以不同。

(3)属性注入(Property Injection)

  在Manager类中公开一个属性,用来设置日志记录对象,Mananger这样定义:

private ILog _logger; ILog Logger get return _logger; set 12 _logger = value; 15 16 }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐