当前位置: 代码迷 >> 综合 >> .net IOC模式(转自http://book.51cto.com/art/200803/67575.htm)
  详细解决方案

.net IOC模式(转自http://book.51cto.com/art/200803/67575.htm)

热度:55   发布时间:2023-12-22 00:09:52.0
2011-09-02 15:17

  控制反转IOC和依赖注入DI

控制反转(Inversion of Control,IOC)和依赖注入(Dependency Injection,DI)基本上是一个意思。不过Martin Fowler在名为《Inversion of Control Containers and the Dependency Injection pattern》的文章中提到,IOC是一个大而化之的概念,因此它倾向于使用DI来介绍这种新模式。所以,下文都将使用依赖注入(DI)来指代这种模式,同时会把实现这种新模式的框架(程序库)按照惯例说成IOC容器。

DI的出现是基于分离关注( Separation of Concerns : SOC)这个原始动力的,同样下面章节要讲到的面向方面编程(Aspect Oriented Programming,AOP)的原始动力。

通过学习GoF设计模式,我们已经习惯一种思维编程方式:接口驱动(Interface Driven Design,IDD),接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等,但是接口一定是需要实现的,也就是如下语句迟早要执行:

IMyClass a = new MyClass();

MyClass是接口IMyClass的一个实现类,而DI模式可以延缓接口的实现,根据需要实现,有个比喻:接口如同空的模型套,在必要时,需要向模型套注射石膏,这样才能成为一个模型实体,因此,我们将人为控制接口的实现成为“注射”。这种方式就是著名的所谓的好莱坞理论:你待着别动,到时我会找你。

下面用一个简单的例子来说明这种模式。这个例子有一个MovieLister类,有一个MoviesDirectedBy的方法根据输入的导演名称来得到所有此导演的电影。

class MovieLister
{
public Movie[] MoviesDirectedBy(string name)
{
IList<Movie> allMovies = finder.FindAll();
List<Movie> lst = new List<Movie>();
foreach (Movie m in allMovies)
{
if (m.Director == name) lst.Add(m);
}
return lst.ToArray();
}
}

通过在MovieLister中使用finder对象,MoviesDirectedBy方法的完成可以不用考虑电影列表的实际存储方式。因而需要认真处理如何把MovieLister对象和finder对象连接起来的问题。首先给finder定义一个接口:

    interface IMovieFinder
{
IList<Movie> FindAll();
}

并实现一个简单的MovieFinder:

    class SimpleMovieFinder:IMovieFinder
{
#region IMovieFinder Members
public IList<Movie> FindAll()
{
List<Movie> lst = new List<Movie>();
Movie m;
for (int i = 0; i < 2; i++)
{
m = new Movie();
m.Director = "Zyg";
lst.Add(m);
}
for (int i = 0; i < 3; i++)
{
m = new Movie();
m.Director = "Kevin";
lst.Add(m);
}
return lst;
}
#endregion
}
现在把MovieFinder和MovieLister耦合起来:
class MovieLister
{
private IMovieFinder finder;
public MovieLister()
{
finder = new SimpleMovieFinder();
}

上面的耦合方式是一种紧耦合方式,如果想把电影列表保存在文本文件或者数据库中,那么在实现类似TextFileMovieFinder类或者 SqlServerMovieFinder类之后,如何不改变MovieLister的代码,而方便地切换到不同的数据源呢?所以依赖注入就是这样一种机制:MovieFinder的实现类不是在编译期连入程序之中的,而是允许在运行期插入具体的实现类,插入动作完全脱离原作者的控制。我们可以把后期插入的这些实现类统称为插件。实际上,要实现这种效果,不一定要依靠依赖注入,使用Service Locator模式也可获得同样的效果。

为了使应用程序获得依赖注入这种特性,一般情况下都会利用一些现成的IOC容器(框架)来实现。后文,会介绍如何使用Castle项目的IOC容器来解决我们这个电影列表的依赖问题。

依赖注入有三种基本的形式:

1.构造器注入(Constructor Injection),即通过构造方法完成依赖关系。如:

public class Sport
{
private InterfaceBall ball;
public Sport(InterfaceBall arg)
{
ball = arg;
}
}

2.设值方法注入(Setter Injection),在类中暴露setter方法来实现依赖关系。如:

public class Sport
{
private InterfaceBall ball;
public void setBall(InterfaceBall arg)
{
ball = arg;
}
}

3.接口注入(Interface Injection),利用接口将调用者与实现者分离。如:

public class Sport
{
private InterfaceBall ball; //InterfaceBall是定义的接口
public void init()
{
//Basketball实现了InterfaceBall接口
ball = (InterfaceBall) Class.forName("Basketball").newInstance();
}
}

Sport类在编译期依赖于InterfaceBall的实现,为了将调用者与实现者分离,我们动态生成Basketball类并将强制类型转换为 InterfaceBall。

  相关解决方案