六大设计原则_第1页
六大设计原则_第2页
六大设计原则_第3页
六大设计原则_第4页
六大设计原则_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

六大设计原则——设计模式之禅秦小波Contents单一职责原则1里氏替换原则2依赖倒置原则3接口隔离原则4迪米特法则5开闭原则6单一职责原则单一职责原则(SingleResponsibilityPrinciple,SRP):Thereshouldneverbemorethanonereasonforaclasstochange.应该有且仅有一个原因引起类的变更

基于角色的访问控制:用户管理修改用户信息信息增加机构(一个人属于多个机构)增加角色设计问题用户的属性和行为没有分开收集和反馈用户信息完成用户信息的维护和变更为什么要把一个接口拆分成两个呢?——单一职责原则在实际的使用中,更倾向于使用两个不用的类或接口,如右图所示:单一职责原则举例单一职责原则Iphone这个接口有两个职责:一个是协议管理,一个是数据传送;其中diag()和huangup()两个方法实现的是协议管理,拨号接通和关闭;Chat()和answer()是数据的传送,把说的话转换成模拟信号或者是数字信号传递到对方,然后再把对方传递的信号转换。问题:1.两个职责都能引起类的变化吗?2.两个变化会相互影响吗?这个Iphone接口包含了两个职责,而且这两个职责的变化不相互影响,那就考虑拆开成两个接口。单一职责原则单一职责原则的优点:类的复杂性降低:实现什么职责都有清晰明确的定义;可读性提高:复杂性降低,可读性就会提高;可维护性提高变更引起的风险降低:变更是必不可少的,接口的单一职责做好的话,一个接口修改只对相应的类有影响,与其他接口无影响,这对项目有非常大的帮助对于接口,设计时要做到单一,但是对于实现类就要多方考虑了,硬套单一职责原则会引起类的剧增,给维护带来非常多的麻烦,过分的细分类也人为的制造系统的负担。继承机制的优缺点在面向对象的语言中,继承是必不可少的、非常优秀的语言机制,它有如下优点:代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;提高代码的重用性;子类可以形似父类,但又异于父类;提高代码的可扩展性;提高产品或项目的开放性。自然界的所有事物都是有点和缺点并存的,继承的缺点如下:继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;降低了代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束;增强了耦合性。当父类的常量、变量和方法被修改时,必须要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大片的代码需要重构。继承机制的优缺点里氏替换原则问题:怎样才能让继承机制的“利”大于“弊”?引入里氏替换原则里氏替换原则最正宗的定义:Ifforeachobjecto1oftypeSthereisanobjecto2oftypeTsuchthatforallprogramsPdefinedintermsofT,thebehaviorofPisunchangedwheno1issubstitutedforo2thenSisasubtypeofT.(如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。)里氏替换原则通俗讲,只要父类出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是反过来就不行了,有子类出现的地方,父类未必就能适应。1、子类完全继承父类的方法代码清单场景类源码Publicclassclient{Publicstaticvoidmain(string[]args){//产生三毛这个士兵SoldiersanMao=newSoldier();//给三毛一支枪sanMao.setGun(newRifle());sanMao.killEnemy();}}结果:士兵开始杀敌人…步枪射击…注意:在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。问:如果有一个玩具枪呢?里氏替换原则玩具枪不能杀敌,射不出子弹,在这种情况下,我们发现业务调用类已经出现了问题,正常的业务逻辑已经不能运行,怎么办?两种解决办法:在Soldier类中增加instanceof的判断,如果是玩具枪,就不用来杀敌人。这个方法可以解决问题,但是要知道,在程序中,每增加一个类,所有与这个父类有关的类都必须修改,可行吗?ToyGun脱离继承,建立一个独立的父类,为了实现代码复用,可以与AbastractGun建立关联委托关系。如下图里氏替换原则注意:如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。2、子类可以有自己的个性子类当然可以有自己的行为和外观了,也就是方法和属性,那这里为什么要再提呢?是因为里氏替换原则可以正着用,但是不能反过来用。在子类出现的地方,父类未必就可以胜任。在这里,系统直接调用了子类,狙击手是很依赖枪支的,别说换一个型号的枪了,就是换一个同型号的枪也会影响射击,所以这里就直接把子类传递了进来。这个时候,我们能不能直接使用父类传递进来呢?里氏替换原则3、覆盖或实现父类的方法时输入参数可以被放大4、复写或实现父类的方法时输出结果可以被缩小依赖倒置原则依赖倒置原则(DependenceInversionPrinciple,DIP):Highlevelmodulesshouldnotdependuponlowlevelmodules.Bothshoulddependuponabstractions.Abstractionsshouldnotdependupondetails.Detailsshoulddependuponabstractions.依赖倒置原则依赖倒置原则包含三层含义:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。在java语言中,抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。依赖倒置原则依赖倒置原则在java语言中的表现就是:模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;接口或抽象类不依赖于实现类;实现类依赖接口或抽象类。采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。注意:设计是否具备稳定性,只要适当地“松松土”,观察“设计的蓝图”是否还可以茁壮地成长就可以得出结论,稳定性较高的设计,在周围环境频繁变化的时候,依然可以做到“我自岿然不动”。在20世纪90年代“个人英雄主义”编程模式还是比较适用的,一个人完成所有的代码工作。但在现在的大中型项目中已经完全不能胜任了,一个项目是一个团队协作的结果,一个“英雄”再厉害也不可能了解所有的业务和所有的技术,要协作就要并行开发,要并行开发就要解决模块之间的项目依赖关系,那么就需要依赖倒置原则。在业务场景中,我们贯彻“抽象不应该依赖细节”,也就是我们认为抽象(ICar接口)不依赖BMW和Benz两个实现类(细节),因此在高层次的模块中应用都是抽象。Client属于高层业务逻辑,它对低层模块的依赖都建立在抽象上,zhangSan的表面类型是IDriver,Benz的表面类型是ICar,是一个接口,是抽象的、非实体化的,在其后的所有操作中,zhangSan都是以IDriver类型进行操作,屏蔽了细节对抽象的影响。当然,张三如果要开宝马车,也很容易,我们只要修改业务场景类就可以实现。在增加低层模块时,只修改了业务场景类,也就是高层模块,对其他低层模块如Driver类不需要做任何修改,业务就可以运行,把“变更”引起的风险扩散降低到最小。注意:在java中,只要定义变量就必然要有类型,一个变量可以有两种类型:表面类型和实际类型,表面类型是在定义的时候赋予的类型,实际类型是对象的类型,如zhangSan的表面类型是IDriver,实际类型是Driver。我们再来思考依赖倒置对并行开发的影响。两个类之间有依赖关系,只要制定出两者之间的接口(或抽象类)就可以独立开发了。依赖的三种写法依赖是可以传递的,A对象依赖B对象,B又依赖C,C又依赖D……生生不息,依赖不止,记住一点:只要做到抽象依赖,即使是多层的依赖传递也无所畏惧!对象的依赖关系有三种方式来传递,构造函数传递依赖对象Setter方法传递依赖对象接口声明依赖对象1.构造函数传递依赖对象在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入,按照这种方式的注入,IDriver和Driver的程序修改后代码如下:2.Setter方法传递依赖对象在抽象中设置Setter方法声明依赖关系,依照依赖注入的说法,这事Setter依赖注入,按照这种方式的注入,IDriver和Driver的程序修改后代码如下:3.接口声明依赖对象在接口的方法中声明依赖对象,代码清单3-6就是采用了接口声明依赖的方式,该方法也叫做接口注入。依赖倒置原则优点依赖倒置原则的优点在小型项目中很难体现出来,但是在一个大中型项目中,采用依赖倒置原则有非常多的优点,特别是规避一些非技术因素引起的问题。项目越大,需求变化的概率也越大,通过采用依赖倒置原则设计的接口或抽象类对实现类进行约束,可以减少需求变化引起的工作量剧增的情况。人员变动在大中型项目的维护周期一般都很长,采用依赖倒置原则可以让维护人员轻松地扩展和维护。依赖倒置原则与开闭原则依赖倒置原则是6个原则中最难以实现的原则,它是实现开闭原则的重要途径,依赖倒置原则没有实现,就别想实现对扩展开放,对修改关闭。在项目中,大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。接口隔离原则接口隔离原则定义:客户端不应该依赖它不需要的接口;类间的依赖关系应该建立在最小的接口上。建立单一接口,不要建立臃肿庞大的接口,接口尽量细化,同时接口中的方法尽量少。它要求“尽量使用多个专门的接口”。专门接口指提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿接口,容纳所有的客户端访问。美女何其多,观点各不同问题与改进思考一下IPettyGirl这个接口,这个接口是否做到了最优化设计?接口IPettyGirl的设计是有缺陷的,过于庞大了,容纳了一些可变的因素,根据接口隔离原则,星探AbstractSearcher应该依赖于具有部分特质的女孩子,而我们却把这些特质都封装了起来,放到了一个接口中,封装过度了!以上把一个臃肿的接口变更为两个独立的接口所依赖的原则就是接口隔离原则,让星探AbstractSearcher依赖两个专用的接口比依赖一个综合的接口要灵活。接口是我们设计时对外提供的契约,通过分散定义多个接口,可以预防未来变更的扩散,提高系统的灵活性和可维护性。接口隔离原则包含以下4层含义:接口要尽量小:“小”是由限度的,首先就是不能违反单一职责原则。接口要高内聚:要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。定制服务:定制服务就是单独为一个个体提供优良的服务。接口设计是有限度地迪米特法则迪米特法则的定义:迪米特法则(LawofDemeter,LoD)也称为最少知识原则,一个对象应该对其他对象有最少的了解。一个类应该对自己需要耦合或调用的类知道得最少,被耦合或调用的类的内部如何复杂都和我没有关系,那是你的事情,我就知道你提供的这么多public方法,我就调用这么多,其他的我一概不关心。迪米特法则对类的低耦合提出了明确的要求:1.只和朋友交流朋友类:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。注意:一个类只和朋友交流,不与陌生类交流,不要出现getA().getB().GetC().getD()这种情况,类与类之间的关系是建立在类间的,而不是方法见,因此一个方法尽量不引入一个类中不存在的对象,当然,JDKAPI提供的类除外。2.朋友间也是有距离的朋友

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论