




已阅读5页,还剩32页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1,面向对象设计原则,宋俊杰,2,目标,重新认识一下面向对象了解面向对象设计原则,.,3,重新认识面向对象,通过面向对象编程语言(OOPL)认识到的面向对象,并不是面向对象的全部,甚至只是浅陋的面向对象不是使用了面向对象语言就是实现了面向对象的设计和开发我们不能依赖编程语言的面向对象机制来掌握面向对象OOPL的三大机制“封装、继承、多态”可以表达面向对象的概念,但是没有刻画出面向对象的核心精神。可以用这三大机制做出好的“面向对象设计”也可以做出差的“面向对象的设计”.,4,重新认识面向对象,OOPL没有回答面向对象的根本性问题-我们为什么要面向对象?我们应该怎样实现好的面向对象?我们应该遵循什么样的原则?任何一个严肃的面向对象程序员都要系统的学习面向对象知识,单纯从编程语言上获得的面向对象知识,不能够胜任面向对象设计与开发.,5,举一个例子,示例场景:我们需要设计一个人事管理系统,其中的一个功能是对各种不同的类型员工,计算其当月的工资-不同类型的员工,拥有不同的薪金计算制度。,.,6,机构化做法1。获得人事系统中所有可能的员工类型2。根据不同的员工类型所对应的不同薪金制度,计算其工资,enumEmployeeTypeEngineer;Sales;Manager;,/计算工资程序If(type=EmployeeType.Enginner)elseif(type=EmployeeType.Sales),7,面向对象设计,1根据不同员工设计不同的类,并使这些类继承自一个Employee抽象类,其中有一个抽象方法getSalary.2在各个不同的员工中,根据自己的薪金制度,重写(override)getSalary方法,8,abstractclassEmployeepublicabstractintgetSalary();classSalesextendsEmployeepublicintgetSalary().,classEngineerextendsEmployeepublicintgetSalary()/显示工资程序Employeee=emFactory.getEmployee(id);System.out.println(e.getSalary();,.,9,现在需求变了,示例场景:随着业务的规模的拓展,又出现了更多类型的员工,比如钟点工、计件工等等,这对系统提出了新的挑战原有的程序要改变。结构化做法:几乎所有涉及到员工类型的地方都要做改变这些代码都要重新编译重新部署面向对象做法:只要添加新的员工类,让其继承自Employee抽象方法,并重写getSalary()方法,然后在EmployeeFactory.getEmployee()方法中根据相关条件产生新的员工类型就可以了。其他地方不需要改变.,10,重新认识,对于前面的例子,从宏观上看,面向对象的构建方式跟更能适应软件的变化,能将变化所带来的影响减小到最小。从微观层面来看,面向对象的方式更强调各个类的“责任”,新增员工类型不会影响原来员工类型的实现代码这是符合真实世界的,也更能控制变化所影响的范围,毕竟Engineer类不应该为新增的“钟点工”来买单对象是什么?-从概念层面讲,对象是某种责任的抽象。-从规格层面讲,对象是一系列可以被其他对象使用的接口(API)。-从语言实现层面来看,对象封装了代码和数据(行为和状态)。有了这些认识之后,怎样才能设计“好的面向对象”?-遵循一定的面向对象设计原则-熟悉一些经典的面向对象设计模式.,11,面向对象设计原则,针对接口编程,而不是针对实现编程-客户无需知道所使用对象的特定类型,只需知道对象拥有客户所期望的接口有限使用组合,而不是类继承-类继承通常为“白箱复用”,对象组合通常成为“黑箱复用”。继承在某种程度上破坏了封装性,子类父类耦合度高;而对象组合则只要求被组合对象具有良好定义的接口,耦合度低。封装变化点-使用封装来创建对象之间的分界层,让设计者可以在分界层的一侧进行修改,而不会对另一侧产生不良的影响,从而实现层次间的松耦合。,12,具体的设计原则,单一职责原则(SRP)开放封闭原则(OCP)Liskov替换原则(LSP)依赖倒置原则(DIP)接口隔离原则(ISP),13,单一职责原则,就一个类而言应该仅有一个引起它变化的原因。当需求变化时,该变化就会反映为类的职责变化。如果一个类承担了多个职责,那么引起它变化的原因就有多个。如果一个类承担的职责过多,就等于把这些职责耦合在了一起。一个职责的变化就可能会削弱,或者抑制这个类完成其他职责的能力.如果需求变化总是引起多个职责同时变化,那么我们就不必分离它们推论:只有变化实际发生时才有意义.,14,开放封闭原则OCP,软件实体(类、模块、函数等等)应该是可以扩展的,但是不可以修改的-对扩展是开放的。当需求变化时,我们可以对模块进行扩展,使其具有能够满足那些变化的行为。-对更改是封闭的。对模块进行修改时不必改动模块的源代码(并非绝对,但是应该是最小限度),15,例子,InterfaceShapepublicvoiddraw()classSquareextendsShapepublicvoiddraw()classCircleextendsShapepublicvoiddraw(),classTestpublicstaticvoidmain(Stringargs)Listshapes=/绘制所有图形Iteratoriter=shapes.iterator();while(iter.hasNext()(Shape)iter.next().draw();,如果要绘制一个新的形状,只需要增加一个新的Shape的派生类就行了.(系统的其他地方会有一些改动,但是这里没有改动),16,我说谎了!,上面的例子并不是100%封闭的。如果我们要求所有的圆必须在正方形之前绘制,我们就要改动Test的代码了。一般而言,无论模块多么“封闭”,都会存在一些无法对之封闭的变化。没有对所有情况都贴切的模型。,17,如何对待?,设计人员必须对于他设计的模块应对哪种变化封闭做出选择。必须先猜测出最有可能发生变化的种类,然后构造抽象来隔离那些变化。有时不容易做到,代价有时会比较高,我们希望把OCP应用限定在可能发生的变化上。,18,结论,开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。(对变化进行封装),19,Liskov(里氏)替换原则(LSP),子类型必须能够替换掉它们的基类型,20,一个微妙的违规,正方形是矩形(is-a关系)。正方形继承矩形。,publicclassRectangleprivatedoubleh;privatedoublew;publicvoidsetHeight(doubleh)this.h=h;publicvoidsetWidth(doublew)this.w=w;publicdoublegetHeight()returnthis.h;publicdoublegetWidth()returnthis.w;publicdoublearea()returnthis.getHeight()*this.getWidth();,publicclassSquareextendsRectangleprivatedoubleh;privatedoublew;publicvoidsetHeight(doubleh)this.h=h;this.w=h;publicvoidsetWidth(doublew)this.w=w;this.h=w;publicdoublegetHeight()returnthis.h;publicdoublegetWidth()returnthis.w;,21,publicclassTestpublicvoidfun(Rectangler)r.setHeight(1);r.setWidth(2);System.out.println(r.area();publicstaticvoidmain(Stringargs)Rectangler=newRectangle();Rectangles=newSquare();Testt=newTest();/t.fun(r);t.fun(s);,如果fun方法的参数Rectangle指向的是一个正方形,产生的结果就会让人产生迷惑。结果是4!对于写fun方法的人来讲,他会认为应该是2.,22,IS-A是关于行为的,Square对象的行为方式和函数fun所期望的Rectangle对象的行为方式不相容.对象的行为方式才是软件真正所关注的问题.(关心是不是想象中的那种行为)OOD中IS-A关系是就行为方式而言的.,23,接受缺陷,大多数情况下,接受一个多态行为中的微妙错误会比试着修改设计使之完全符合LSP更为有利.接受缺陷而不是去追求完美是一个工程上权衡的问题.好的工程师知道如何接受缺陷比追求完美更有利不过,不应该轻易放弃LSP原则,24,我们经常用的例子struts,类RequestProcessor里面的代码:protectedActionForwardprocessActionPerform(HttpServletRequestrequest,HttpServletResponseresponse,Actionaction,ActionFormform,ActionMappingmapping)throwsIOException,ServletExceptiontryreturn(action.execute(mapping,form,request,response);catch(Exceptione)return(processException(request,response,e,form,mapping);注意红色部分,25,依赖倒置原则DIP,要依赖于抽象不要依赖于具体抽象不应该依赖于细节,细节应该依赖于抽象另一种说法:要对接口编程,不要针对实现编程.,26,另一种说法的解释,应当使用java接口和抽象java类进行变量的类型声明,参量的类型声明,方法的返回类型声明,以及数据类型的转换等.Vectoremployees=newVector();应该声明为Listemployees=newVector();好处是,将Vector类型转会为ArrayList需要最小的改动.,27,怎样做到,以抽象方式耦合是依赖倒转原则的关键.一个抽象耦合关系总要涉及具体类从抽象类继承,并且保证任何引用到基类的地方都可以换成其子类,因此里氏替换原则是依赖倒置原则的基础.,28,并非完美,抽象层次上的耦合虽然有灵活性,但也带来了额外的复杂性.如果一个具体类发生变化的可能性非常小,那么抽象耦合发挥的好处便十分有限,这时使用具体耦合反而会更好,29,接口隔离原则ISP,接口的污染,一个没有经验的设计师往往想节省接口的数目,将几个功能相近或功能相关的接口合并,并将这看成是代码优化的一部分
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 环保设备制作培训课件
- 航空航天复合材料 课件 第6章 烧蚀防热复合材料朱和国
- 早产儿的治疗及护理
- 餐饮行业知名品牌收购与经营权协议
- 企业财务风险管理与内部控制体系建设合同
- 餐饮企业大堂经理职位竞聘与培养协议
- 拆迁补偿与二手房买卖合同风险评估与解决方案合同
- 幼儿园考勤制度岗前培训
- 水稻专用肥采购合同及技术指导服务协议
- 高新区股权交易纠纷解决及股权转让合同
- 大学生创业文具店计划书
- 职业发展计划和个人成长
- 溶洞相关知识培训课件
- 材料设备进场计划及保证措施
- 机械加工价格表
- 2025年上半年云南省昆明市公安局交通警察支队招聘勤务辅警200人易考易错模拟试题(共500题)试卷后附参考答案
- 医用耗材采购风险管理工作总结
- 催收员26种施压话术集合5篇
- 承包经营合同(2024版)
- CCFA:2024年中国零售数字化及新技术应用创新案例
- UL1741标准中文版-2020逆变器变流器断路器UL标准中文版
评论
0/150
提交评论