


付费下载
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、从针对接口编程到依赖注入1.概况说明2.猫狗大战举例3.说明为什么要针对接口编程,优点4.说明为什么要“依赖抽象,不要依赖具体类”5.说明“依赖倒置”与抽象工厂模式6.说明“将组件的配置与使用分离”7.简单说明依赖注入8.讲解 petshop 依赖注入与它的工厂模式9.讲解 TheBeerHouse依赖注入形式10.几个 .Net 的依赖注入容器11.取舍与适用概况说明现在在各种技术站点、书籍文章上,都能看到IoC 容器、控制反转、依赖注入的字眼,而且还会有一些专门实现这些功能的开发工具:S 、Castal Windsor、Unity 等等。那么这种技术是如何演变而来的?它的适用场景是哪里?我
2、们该不该学习并掌握这门技术?下面我会根据我个人的理解与搜集来的材料做出一些解释。猫狗大战举例我现在要做一个猫狗大战的游戏,系统内部采用了标准的OO 技术,先设计了一个狗狗的抽象类。public abstract class Dog public void Run(); public void Jump(); public void Bay(); public abstract void Display(); 假设游戏中每个狗狗跑的速度、跳的高度、叫的音量都是相同的, 那么唯一不同的就是外貌了,所以Display() 是抽象的。public class Poodle:Dog public ove
3、rride void Display() /我是狮子狗 public class Dachshund:Dog public override void Display() /我是腊肠狗 /其他狗狗 . 好了,现在我们想让游戏中加入打斗的元素,狗狗会攻击,可能你会想到只用在基类中加一个Attact() 的方法,就可以这样让所有继承它的狗狗就都会攻击了。不过问题很快就来了,你会发现 AIBO( 日本产的电子机械宠物狗)包括家里的绒毛玩具狗也会攻击了,这是很不合情理的事情。所以并不是所有的狗狗都会攻击这个行为,那么有人肯定想到使用接口了,把Attact() 这个方法提取到接口中,只让会攻击的狗狗实现
4、这个接口就可以了。public interface IAttact void Attact(); public class Poodle:Dog,IAttact public override void Display() /我是狮子狗 public void Attact() /咬一口 说明为什么要针对接口编程,优点这样看起来很好,但是需求总是在变化的,现在的需求又增加了:要求每种狗狗的攻击方式不同,有的会咬,有的会扑,有的甚至会狮子吼的功夫,当然如果狗狗升级了,还会出现更多的攻击方式。上面这个方式的缺点就显现出来了,代码会在多个子类中重复,无法知道所有狗狗的全部行为,运行时不容易改变等等。
5、下面这样做,我们把变化的部分提取出来,多种行为的实现用接口统一实现。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
6、 SetAttactBehavior(IAttact a) attact=a; public void PerformAttact() attact.Attact(); public override void Display() /我是狮子狗 这样的设计就让狗狗的攻击行为有了弹性,我们可以动态的在运行时改变它的行为,也可以随时在不影响其他类的情况下添加更改行为。而以往的做法是行为来自Dog 基类或者继承接口并由子类自行实现,这两种方法都依赖于“实现”,我们被邦的死死的,而无法更改行为。而接口所表示的行为实现,不会被绑死在Dog 类与子类中。这就是设计模式中的一个原则:针对接口编程,不要针对实
7、现编程。说明为什么要“依赖抽象,不要依赖具体类”但是,当我们使用“new”的时候,就已经在实例化一个具体类了。这就是一种实现,只要有具体类的出现,就会导致代码更缺乏弹性。就好比雕塑家做好了一个“沉思者”,想把它再改造成“维纳斯”,难度可想而知。我们再回到猫狗大战这个游戏,为了增加趣味性,我们增加了猫狗交互的功能,如果你选择了狗狗开始游戏,那么会随机不同的场景,在固定的场景会遇到固定的猫。例如:在峭壁背景会遇到山猫,在象牙塔背景中会遇到波斯猫,在草原中会遇到云猫等。Cat cat; if(mountain) cat=new Catamountain(); else if(ivory) cat=n
8、ew PersianCat(); else if(veldt) cat=new CloudCat(); 但是有时真正要实例化哪些类,要在运行时有一些条件决定。当一旦有变化或扩展时,就要重新打开这段代码进行修改,这就违反了我们“对修改关闭”的原则。这段代码的依赖特别紧密,而且是高层依赖于低层(客户端依赖具体类的实现)。不过庆幸的是, 我们有“依赖倒转原则”与“抽象工厂模式”来拯救我们的代码。说明“依赖倒置”与抽象工厂模式依赖倒转原则是要依赖抽象,不要依赖具体类。也就是说客户端(高层组件 )要依赖于抽象(Cat), 各种猫咪 (低层组件 )也要依赖抽象 (Cat) 。 虽然我们已经创造了一个抽象C
9、at,但我们仍然在代码中实际地创建了具体的 Cat ,这个抽象并没有什么影响力,那么我们如何将这些实例化对象的代码独立出来?工厂模式正好派上用场。工厂模式属于创建型模式,它能将对象的创建集中在一起进行处理。相反如果你选择了猫咪角色,就会在不同的场景遇到特定的狗狗 NPC 。现在我们要创建一个工厂的接口:public interface Factory Cat CreateCat(); Dog CreateDog(); public class MountainSceneFactory:Factory public Cat CreateCat() return new Catamountain(
10、); public Dog CreateDog() return new CragDog(); public class VeldtSceneFactory:Factory public Cat CreateCat() return new CloudCat(); public Dog CreateDog() return new VeldtDog(); 然后构建一个草原的场景: public class VeldtScene : Scene Factory factory; private static Cat cat=null; private static Dog dog=null; p
11、ublic VeldtScene(Factory f) factory=f; Public void prepare() if(User.Identity=Dog) dog=factory.CreateDog(); else(user.Identity=Cat) cat=factory.CreateCat(); 这样一来,场景的条件不由代码来改变,而可以由客户端来动态改变,来看看我们的客户端吧!Factory factory=new VeldtSceneFactory(); Scene scene=new VeldtScene(factory); Scene.prepare(); 这样如果你的
12、角色是一只狗狗的话,就能在这个草原上见到一只云猫了。工厂模式将实例解耦出来,替换不同的工厂以取得不同的行为。说明“将组件的配置与使用分离”事物总是在发展,需求总是在增加。猫狗大战要升级为网络版,我们希望由开发人员开发游戏,而由技术支持人员做游戏的安装配置。一般开发者会提供配置文件交给技术支持人员,由他们来动态的为游戏更改配置,例如在草原上出现了波斯猫,老虎却出现在客厅里。技术支持人员是无法修改源代码的,但可以让他们修改配置文件以来改变实例的创建。我们的设计离不开一个基本原则-分离接口与实现。在面向对象程序里,我们在一个地方用条件逻辑来决定具体实例化哪一个类,以后的条件分支都由多态来实现,而不是
13、继续重复前面的条件逻辑。当我们决定将“选择具体实现类”的据侧推迟到部署阶段,则在装配原则上是要与应用程序的其余部分分开的,这样我就可以轻松的针对不同的部署替换不同的配置。简单说明依赖注入终于可以进入本文的重点了。现在我们的目标就是要把组件的配置与使用分离开。IoC(Inversion of Control控制反转)容器因此应运而生,martin 在他的大作中将此更形象的称谓依赖注入 (Dependency Injection)。依赖注入的基本思想是:用一个单独的对象获得接口的一个合适的实现,并将其实例赋给调用者的一个字段。具体的依赖注入的讲解可以看Martin Fowler的文章,不再详述。我
14、主要以实例的形式,来更好的理解依赖注入的特点与其所带来的好处。讲解 petshop 依赖注入与它的工厂模式PetShop4.0 是一个微软发布的开源Web 应用程序, 它的经典的三层架构已经成了学习架构模式的必修课程,它提供了针对 SqlServer 与 Oracle 的数据访问层以方便不同的使用者在这两种数据库环境中部署应用程序,部署者只用简单的在配置文件中修改,就可以轻松的在两种环境中进行切换,这一切都得住于依赖注入。抽象出来的IDAL 模块脱离了与具体数据库的依赖,从而使整个数据访问层利于数据库的迁移。DALFactory模块专门管理DAL 对象的创建,以便于BLL 的访问,SQLSer
15、verDAL和 OracleDAL模块均实现了IDAL 的接口,其中包含的逻辑就是对数据库的CRUD 操作,因数据库不同,代码也会有所不同。当创建SQLServer的 Order 对象时:PetShopFactory factory=new SQLServerFactory(); IOrder=factory.CreateOrder(); 这里 new 出来一个具体实现类SQLServerFactory一旦要更换 Oracle , 不可避免要修改代码, 但若用了依赖注入,一切问题迎刃而解。PetShop 的 Web.config文件中:<appSettings> &
16、amp;lt;add key=WebDAL value=PetShop.SQLServerDAL/> </appSettings> 在 DALFactory中的 DataAccess中,首先读出Web.config的配置,然后运用反射技术创建对象实例:private static readonly string path = ConfigurationManager.AppSettingsWebDAL; public static PetShop.IDAL.ICategory CreateCategory() string className = pa
17、th + .Category; return (PetShop.IDAL.ICategory)Assembly.Load(path).CreateInstance(className); BLL 层调用的话,只需把创建的实力赋值给一个私有的字段:private static readonly ICategory dal = PetShop.DALFactory.DataAccess.CreateCategory(); 实例的创建只是通过反射将配置注入进程序中,若要更改为Oracle ,仅需把 value=PetShop.SQLServerDAL更改为value=PetShop.OracleDA
18、L!但是不要以为我们因此可以按照这个模式将所有的程序更改为这种类型的, PetShop 是共享程序。 部署环境因机而异,依赖注入在这里很有必要性。若我们的应用程序的部署环境永远不会改变的话,完全没有必要应用依赖注入改变数据库,相反还会增加程序复杂度和因反射带来的20% 性能损失。讲解 TheBeerHouse依赖注入形式接着再来看看另一个依赖注入的实现方式。TheBeerHouse是最先发布在微软Startkits软件发布区的,国内有它的讲解书籍,开发者与作者是同一个人。TBH 为了实现数据库环境的移植,采用了与 PetShop 截然不同的依赖注入形式,首先它在配置文件中自定义配置,将各个模块
19、的配置参数都写在了里面,然后ConfigSection中对所有配置写了默认配置并可对这些配置读写。如在Articles 中:ConfigurationProperty(providerType, DefaultValue = MB.TheBeerHouse.DAL.SqlClient.SqlArticlesProvider) public string ProviderType get return (string)baseproviderType; set baseproviderType = value; 它的默认提供程序即为MB.TheBeerHouse.DAL.SqlClient.Sq
20、lArticlesProvider。这里没有接口的实现,而是以继承的方式。DataAccess基类其实相当于一个简单的SQLHelper ,定义了一些如连接符属性和 Execute 方法。几大模块的Provider 继承了这个DataAccess ,写了一些需要继承的CRUD 方法,最重要的一点是应用单件模式与依赖注入创建并返回了此Provider的实例。static private ArticlesProvider _instance = null; static public ArticlesProvider Instance get if (_instance = null) _inst
21、ance = (ArticlesProvider)Activator.CreateInstance( Type.GetType(Globals.Settings.Articles.ProviderType); return _instance; 作者或许也认为这些实例的创建分散于各大Provider ,不易调用,于是又写了一个SiteProvider :public static class SiteProvider public static ArticlesProvider Articles get return ArticlesProvider.Instance; /. 这其实正是一个简
22、单工厂方法!用属性的方式是为了更方便方法的调用。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这两个开源框架做开发,倒是也珠联璧合相辅相成。 但是 Sp
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年厨房设备进出口贸易代理协议
- 二零二五年度文化娱乐项目开发合同摘要
- 2025版摩托车售后服务网点加盟协议
- 二零二五年度教育行业贷款购销合同
- 二零二五版智能硬件研发联合出资合作协议
- 2025版便利店连锁加盟品牌推广合作合同
- 二零二五年度房屋买卖合同样本及房地产交易税费减免协议
- 二零二五年度抵押资产购销法律咨询及服务合同
- 2025版股权质押借款跨境投资合作合同
- 2025车库租赁合同范本汇编:车位租赁合同签订指南
- 重症患者目标导向性镇静课件
- 混凝土养护方案
- 高质量SCI论文入门必备从选题到发表全套课件
- 长螺旋钻孔咬合桩基坑支护施工工法
- 库欣综合征英文教学课件cushingsyndrome
- 220kv升压站质量评估报告
- C语言程序设计(第三版)全套教学课件
- 未来医美的必然趋势课件
- 附件1发电设备备品备件验收及仓储保养技术标准
- 12、信息通信一体化调度运行支撑平台(SG-I6000)第3-8部分:基础平台-系统安全防护
- 大连市劳动用工备案流程
评论
0/150
提交评论