从针对接口编程到依赖注入
2009-04-06 19:20
387 查看
1.概况说明
2.猫狗大战举例
3.说明为什么要针对接口编程,优点
4.说明为什么要“依赖抽象,不要依赖具体类”
5.说明“依赖倒置”与抽象工厂模式
6.说明“将组件的配置与使用分离”
7.简单说明依赖注入
8.讲解petshop依赖注入与它的工厂模式
9.讲解TheBeerHouse依赖注入形式
10.几个.Net的依赖注入容器
11.取舍与适用
概况说明
现在在各种技术站点、书籍文章上,都能看到IoC容器、控制反转、依赖注入的字眼,而且还会有一些专门实现这些功能的开发工具:Spring.net、 Castal Windsor、Unity等等。那么这种技术是如何演变而来的?它的适用场景是哪里?我们该不该学习并掌握这门技术?下面我会根据我个人的理解与搜集来的材料做出一些解释。
猫狗大战举例
我现在要做一个猫狗大战的游戏,系统内部采用了标准的OO技术,先设计了一个狗狗的抽象类。
public abstract class Dog
{
public void Run();
public void Jump();
public void Bay();
public abstract void Display();
}
假设游戏中每个狗狗跑的速度、跳的高度、叫的音量都是相同的,那么唯一不同的就是外貌了,所以 Display()是抽象的。
public class Poodle:Dog
{
public override void Display()
{
//我是狮子狗
}
}
public class Dachshund:Dog
{
public override void Display()
{
//我是腊肠狗
}
}
//其他狗狗.
好了,现在我们想让游戏中加入打斗的元素,狗狗会攻击,可能你会想到只用在基类中加一个Attact()的方法,就可以这样让所有继承它的狗狗就都会攻击了。不过问题很快就来了,你会发现AIBO(日本产的电子机械宠物狗)包括家里的绒毛玩具狗也会攻击了,这是很不合情理的事情。所以并不是所有的狗狗都会攻击这个行为,那么有人肯定想到使用接口了,把Attact()这个方法提取到接口中,只让会攻击的狗狗实现这个接口就可以了。
public interface IAttact
{
void Attact();
}
public class Poodle:Dog,IAttact
{
public override void Display()
{
//我是狮子狗
}
public void Attact()
{
//咬一口
}
}
说明为什么要针对接口编程,优点
这样看起来很好,但是需求总是在变化的,现在的需求又增加了:要求每种狗狗的攻击方式不同,有的会咬,有的会扑,有的甚至会狮子吼的功夫,当然如果狗狗升级了,还会出现更多的攻击方式。上面这个方式的缺点就显现出来了,代码会在多个子类中重复,无法知道所有狗狗的全部行为,运行时不容易改变等等。
下面这样做,我们把变化的部分提取出来,多种行为的实现用接口统一实现。
public class BiteAttact:IAttact
{
public void Attact()
{
//咬
}
}
public class SnapAttact:IAttact
{
public void Attact()
{
//扑咬
}
}
//其他实现
当我们想要增加一种行为方式时,只需继承接口就可以,并不会改变其他行为。
public class Poodle:Dog
{
IAttact attact;
public Poodle()
{
attact=new BiteAttact();
}
//这里我在调用的时候就可以动态的设定行为了
public void SetAttactBehavior(IAttact a)
{
attact=a;
}
public void PerformAttact()
{
attact.Attact();
}
public override void Display()
{
//我是狮子狗
}
}
这样的设计就让狗狗的攻击行为有了弹性,我们可以动态的在运行时改变它的行为,也可以随时在不影响其他类的情况下添加更改行为。而以往的做法是行为来自 Dog基类或者继承接口并由子类自行实现,这两种方法都依赖于“实现”,我们被邦的死死的,而无法更改行为。而接口所表示的行为实现,不会被绑死在Dog 类与子类中。这就是设计模式中的一个原则:针对接口编程,不要针对实现编程。
说明为什么要“依赖抽象,不要依赖具体类”
但是,当我们使用“new”的时候,就已经在实例化一个具体类了。这就是一种实现,只要有具体类的出现,就会导致代码更缺乏弹性。就好比雕塑家做好了一个“沉思者”,想把它再改造成“维纳斯”,难度可想而知。
我们再回到猫狗大战这个游戏,为了增加趣味性,我们增加了猫狗交互的功能,如果你选择了狗狗开始游戏,那么会随机不同的场景,在固定的场景会遇到固定的猫。例如:在峭壁背景会遇到山猫,在象牙塔背景中会遇到波斯猫,在草原中会遇到云猫等。
Cat cat;
if(mountain){
cat=new Catamountain();
}else if(ivory){
cat=new PersianCat();
}else if(veldt){
cat=new CloudCat();
}
但是有时真正要实例化哪些类,要在运行时有一些条件决定。当一旦有变化或扩展时,就要重新打开这段代码进行修改,这就违反了我们“对修改关闭”的原则。这段代码的依赖特别紧密,而且是高层依赖于低层(客户端依赖具体类的实现)。不过庆幸的是,我们有“依赖倒转原则”与“抽象工厂模式”来拯救我们的代码。
说明“依赖倒置”与抽象工厂模式
依赖倒转原则是要依赖抽象,不要依赖具体类。也就是说客户端(高层组件)要依赖于抽象(Cat),各种猫咪(低层组件)也要依赖抽象(Cat)。虽然我们已经创造了一个抽象Cat,但我们仍然在代码中实际地创建了具体的Cat,这个抽象并没有什么影响力,那么我们如何将这些实例化对象的代码独立出来?工厂模式正好派上用场。工厂模式属于创建型模式,它能将对象的创建集中在一起进行处理。
相反如果你选择了猫咪角色,就会在不同的场景遇到特定的狗狗NPC。
.
}
这其实正是一个简单工厂方法!用属性的方式是为了更方便方法的调用。
BLL调用Articles的方法时,只需直接调用SiteProvider.Articles.GetArticleCount();
更换Oracle,写相应的类继承这几大模块的Provider,并设置配置providerType为相应的提供程序。
相对来说,PetShop依赖注入的形式更简洁明了,而TBH采用了自定义配置而更显得灵活多变。
几个.Net的依赖注入容器
既然有依赖注入模式的出现,就会有针对它而发展的框架。IoC容器最先是在Java阵营中出现并发展的,.Net阵营中实现依赖注入的框架作为后起之秀,也出现了Spring.Net,Castal Windsor,Unity优秀的依赖注入框架。我们可以不去掌握这些框架的使用,但学习他们可以使我们的编码更标准更快捷,也令我们对依赖注入的理解更透彻深入。
Spring.Net是由Java火的不能再火的的Spring演变过来的,它是一个关注于.NET企业应用开发的应用程序框架。它能够提供宽广范围的功能,例如依赖注入、面向方面编程(AOP)、数据访问抽象, 以及ASP.NET集成等。现在相当多的人用Spring.Net+NHibernate这两个开源框架做开发,倒是也珠联璧合相辅相成。但是Spring.Net贯彻的思想是一切皆配置,从头到尾都是配置,往往不着道的话会被这一连串的配置文件搞花了眼。
相比来说,Castal Windsor的配置简单的多了,对于对象之间的依赖关系,Castle IOC会自动去连接,缺点是如果有多个类(组件)实现同一个接口(服务),容器会自动选择最先加入到容器中的组件来装配。“Windsor是Castle的一个IOC容器。它构建于MicroKernel之上,功能非常之强大,能检测类并了解使用这些类时需要什么参数,检测类型和类型之间工作依赖性,并提供服务或者发生错误时提供预警的机制。”
最后出场的是微软P&P小组的Unity容器,它在Enterprise Library4.0中提供.“Unity是一个轻量级的、可扩展的依赖注入容器,容器靠使用构造器、属性和方法的方式来实现注入,你可以单独的使用Unity而不需要安装Enterprise Library,Unity为Enterprise Library的对象产生提供了一种新的方式。”Unity与Windsor的方式基本相似,而且都是创建容器、注册接口映射、获取对象实例三个步骤。
若要实现依赖注入,这三种容易都是不错的选择,具体看你得习惯与专长了。有关这三个容器的使用方法,我会在以后的文章中一起放出,这里只对它们作简单的介绍。
取舍与适用
总体来说,依赖注入的适用场景就在于---变化,我们预先根据经验预料或者后期重构在某个地方会产生变化,那么就可以将依赖解耦,采用外部文件的方式动态的将对象的创建注入进程序内。若没有变化产生也硬要采用依赖注入模式的话,就会有过度设计的问题出现了。
文章内的例子和语言可能还有很多不恰当的地方,但对依赖注入这门技术的产生与发展有了更深的认识,我的目的也就达到了。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明
2.猫狗大战举例
3.说明为什么要针对接口编程,优点
4.说明为什么要“依赖抽象,不要依赖具体类”
5.说明“依赖倒置”与抽象工厂模式
6.说明“将组件的配置与使用分离”
7.简单说明依赖注入
8.讲解petshop依赖注入与它的工厂模式
9.讲解TheBeerHouse依赖注入形式
10.几个.Net的依赖注入容器
11.取舍与适用
概况说明
现在在各种技术站点、书籍文章上,都能看到IoC容器、控制反转、依赖注入的字眼,而且还会有一些专门实现这些功能的开发工具:Spring.net、 Castal Windsor、Unity等等。那么这种技术是如何演变而来的?它的适用场景是哪里?我们该不该学习并掌握这门技术?下面我会根据我个人的理解与搜集来的材料做出一些解释。
猫狗大战举例
我现在要做一个猫狗大战的游戏,系统内部采用了标准的OO技术,先设计了一个狗狗的抽象类。
public abstract class Dog
{
public void Run();
public void Jump();
public void Bay();
public abstract void Display();
}
假设游戏中每个狗狗跑的速度、跳的高度、叫的音量都是相同的,那么唯一不同的就是外貌了,所以 Display()是抽象的。
public class Poodle:Dog
{
public override void Display()
{
//我是狮子狗
}
}
public class Dachshund:Dog
{
public override void Display()
{
//我是腊肠狗
}
}
//其他狗狗.
好了,现在我们想让游戏中加入打斗的元素,狗狗会攻击,可能你会想到只用在基类中加一个Attact()的方法,就可以这样让所有继承它的狗狗就都会攻击了。不过问题很快就来了,你会发现AIBO(日本产的电子机械宠物狗)包括家里的绒毛玩具狗也会攻击了,这是很不合情理的事情。所以并不是所有的狗狗都会攻击这个行为,那么有人肯定想到使用接口了,把Attact()这个方法提取到接口中,只让会攻击的狗狗实现这个接口就可以了。
public interface IAttact
{
void Attact();
}
public class Poodle:Dog,IAttact
{
public override void Display()
{
//我是狮子狗
}
public void Attact()
{
//咬一口
}
}
说明为什么要针对接口编程,优点
这样看起来很好,但是需求总是在变化的,现在的需求又增加了:要求每种狗狗的攻击方式不同,有的会咬,有的会扑,有的甚至会狮子吼的功夫,当然如果狗狗升级了,还会出现更多的攻击方式。上面这个方式的缺点就显现出来了,代码会在多个子类中重复,无法知道所有狗狗的全部行为,运行时不容易改变等等。
下面这样做,我们把变化的部分提取出来,多种行为的实现用接口统一实现。
public class BiteAttact:IAttact
{
public void Attact()
{
//咬
}
}
public class SnapAttact:IAttact
{
public void Attact()
{
//扑咬
}
}
//其他实现
当我们想要增加一种行为方式时,只需继承接口就可以,并不会改变其他行为。
public class Poodle:Dog
{
IAttact attact;
public Poodle()
{
attact=new BiteAttact();
}
//这里我在调用的时候就可以动态的设定行为了
public void SetAttactBehavior(IAttact a)
{
attact=a;
}
public void PerformAttact()
{
attact.Attact();
}
public override void Display()
{
//我是狮子狗
}
}
这样的设计就让狗狗的攻击行为有了弹性,我们可以动态的在运行时改变它的行为,也可以随时在不影响其他类的情况下添加更改行为。而以往的做法是行为来自 Dog基类或者继承接口并由子类自行实现,这两种方法都依赖于“实现”,我们被邦的死死的,而无法更改行为。而接口所表示的行为实现,不会被绑死在Dog 类与子类中。这就是设计模式中的一个原则:针对接口编程,不要针对实现编程。
说明为什么要“依赖抽象,不要依赖具体类”
但是,当我们使用“new”的时候,就已经在实例化一个具体类了。这就是一种实现,只要有具体类的出现,就会导致代码更缺乏弹性。就好比雕塑家做好了一个“沉思者”,想把它再改造成“维纳斯”,难度可想而知。
我们再回到猫狗大战这个游戏,为了增加趣味性,我们增加了猫狗交互的功能,如果你选择了狗狗开始游戏,那么会随机不同的场景,在固定的场景会遇到固定的猫。例如:在峭壁背景会遇到山猫,在象牙塔背景中会遇到波斯猫,在草原中会遇到云猫等。
Cat cat;
if(mountain){
cat=new Catamountain();
}else if(ivory){
cat=new PersianCat();
}else if(veldt){
cat=new CloudCat();
}
但是有时真正要实例化哪些类,要在运行时有一些条件决定。当一旦有变化或扩展时,就要重新打开这段代码进行修改,这就违反了我们“对修改关闭”的原则。这段代码的依赖特别紧密,而且是高层依赖于低层(客户端依赖具体类的实现)。不过庆幸的是,我们有“依赖倒转原则”与“抽象工厂模式”来拯救我们的代码。
说明“依赖倒置”与抽象工厂模式
依赖倒转原则是要依赖抽象,不要依赖具体类。也就是说客户端(高层组件)要依赖于抽象(Cat),各种猫咪(低层组件)也要依赖抽象(Cat)。虽然我们已经创造了一个抽象Cat,但我们仍然在代码中实际地创建了具体的Cat,这个抽象并没有什么影响力,那么我们如何将这些实例化对象的代码独立出来?工厂模式正好派上用场。工厂模式属于创建型模式,它能将对象的创建集中在一起进行处理。
相反如果你选择了猫咪角色,就会在不同的场景遇到特定的狗狗NPC。
.
}
这其实正是一个简单工厂方法!用属性的方式是为了更方便方法的调用。
BLL调用Articles的方法时,只需直接调用SiteProvider.Articles.GetArticleCount();
更换Oracle,写相应的类继承这几大模块的Provider,并设置配置providerType为相应的提供程序。
相对来说,PetShop依赖注入的形式更简洁明了,而TBH采用了自定义配置而更显得灵活多变。
几个.Net的依赖注入容器
既然有依赖注入模式的出现,就会有针对它而发展的框架。IoC容器最先是在Java阵营中出现并发展的,.Net阵营中实现依赖注入的框架作为后起之秀,也出现了Spring.Net,Castal Windsor,Unity优秀的依赖注入框架。我们可以不去掌握这些框架的使用,但学习他们可以使我们的编码更标准更快捷,也令我们对依赖注入的理解更透彻深入。
Spring.Net是由Java火的不能再火的的Spring演变过来的,它是一个关注于.NET企业应用开发的应用程序框架。它能够提供宽广范围的功能,例如依赖注入、面向方面编程(AOP)、数据访问抽象, 以及ASP.NET集成等。现在相当多的人用Spring.Net+NHibernate这两个开源框架做开发,倒是也珠联璧合相辅相成。但是Spring.Net贯彻的思想是一切皆配置,从头到尾都是配置,往往不着道的话会被这一连串的配置文件搞花了眼。
相比来说,Castal Windsor的配置简单的多了,对于对象之间的依赖关系,Castle IOC会自动去连接,缺点是如果有多个类(组件)实现同一个接口(服务),容器会自动选择最先加入到容器中的组件来装配。“Windsor是Castle的一个IOC容器。它构建于MicroKernel之上,功能非常之强大,能检测类并了解使用这些类时需要什么参数,检测类型和类型之间工作依赖性,并提供服务或者发生错误时提供预警的机制。”
最后出场的是微软P&P小组的Unity容器,它在Enterprise Library4.0中提供.“Unity是一个轻量级的、可扩展的依赖注入容器,容器靠使用构造器、属性和方法的方式来实现注入,你可以单独的使用Unity而不需要安装Enterprise Library,Unity为Enterprise Library的对象产生提供了一种新的方式。”Unity与Windsor的方式基本相似,而且都是创建容器、注册接口映射、获取对象实例三个步骤。
若要实现依赖注入,这三种容易都是不错的选择,具体看你得习惯与专长了。有关这三个容器的使用方法,我会在以后的文章中一起放出,这里只对它们作简单的介绍。
取舍与适用
总体来说,依赖注入的适用场景就在于---变化,我们预先根据经验预料或者后期重构在某个地方会产生变化,那么就可以将依赖解耦,采用外部文件的方式动态的将对象的创建注入进程序内。若没有变化产生也硬要采用依赖注入模式的话,就会有过度设计的问题出现了。
文章内的例子和语言可能还有很多不恰当的地方,但对依赖注入这门技术的产生与发展有了更深的认识,我的目的也就达到了。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明
相关文章推荐
- 从针对接口编程到依赖注入
- 从针对接口编程到依赖注入
- 从针对接口编程到依赖注入
- 从针对接口编程到依赖注入
- 从针对接口编程到依赖注入
- 自学简述OOP编程中接口的重要性-依赖注入
- Spring依赖注入与配合接口编程案例
- dubbo接口可以依赖注入但是调用失败报错
- 一篇能很好反映普通接口多态 工厂模式 依赖注入三者的耦合强度区别的文章
- 针对接口编程
- 一篇能很好反映普通接口多态 工厂模式 依赖注入三者的耦合强度区别的文章
- 针对接口编程
- C#的接口实现的依赖倒置、控制反转、依赖注入
- 我对针对接口编程的浅解
- 依赖倒转原则(针对接口编程,而非实现编程)
- spring接口实现类 依赖注入
- 针对接口编程
- 针对接口编程,而不是针对实现编程
- 针对接口编程,不要针对实现编程
- 依赖注入之接口注入