




已阅读5页,还剩32页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
面向对象设计原则 宋俊杰 目标 重新认识一下面向对象了解面向对象设计原则 重新认识面向对象 通过面向对象编程语言 OOPL 认识到的面向对象 并不是面向对象的全部 甚至只是浅陋的面向对象不是使用了面向对象语言就是实现了面向对象的设计和开发我们不能依赖编程语言的面向对象机制来掌握面向对象OOPL的三大机制 封装 继承 多态 可以表达面向对象的概念 但是没有刻画出面向对象的核心精神 可以用这三大机制做出好的 面向对象设计 也可以做出差的 面向对象的设计 重新认识面向对象 OOPL没有回答面向对象的根本性问题 我们为什么要面向对象 我们应该怎样实现好的面向对象 我们应该遵循什么样的原则 任何一个严肃的面向对象程序员都要系统的学习面向对象知识 单纯从编程语言上获得的面向对象知识 不能够胜任面向对象设计与开发 举一个例子 示例场景 我们需要设计一个人事管理系统 其中的一个功能是对各种不同的类型员工 计算其当月的工资 不同类型的员工 拥有不同的薪金计算制度 机构化做法1 获得人事系统中所有可能的员工类型2 根据不同的员工类型所对应的不同薪金制度 计算其工资 enumEmployeeType Engineer Sales Manager 计算工资程序If type EmployeeType Enginner elseif type EmployeeType Sales 面向对象设计 1根据不同员工设计不同的类 并使这些类继承自一个Employee抽象类 其中有一个抽象方法getSalary 2在各个不同的员工中 根据自己的薪金制度 重写 override getSalary方法 abstractclassEmployee publicabstractintgetSalary classSalesextendsEmployee publicintgetSalary classEngineerextendsEmployee publicintgetSalary 显示工资程序Employeee emFactory getEmployee id System out println e getSalary 现在需求变了 示例场景 随着业务的规模的拓展 又出现了更多类型的员工 比如钟点工 计件工 等等 这对系统提出了新的挑战 原有的程序要改变 结构化做法 几乎所有涉及到员工类型的地方都要做改变 这些代码都要重新编译重新部署 面向对象做法 只要添加新的员工类 让其继承自Employee抽象方法 并重写getSalary 方法 然后在EmployeeFactory getEmployee 方法中根据相关条件产生新的员工类型就可以了 其他地方不需要改变 重新认识 对于前面的例子 从宏观上看 面向对象的构建方式跟更能适应软件的变化 能将变化所带来的影响减小到最小 从微观层面来看 面向对象的方式更强调各个类的 责任 新增员工类型不会影响原来员工类型的实现代码 这是符合真实世界的 也更能控制变化所影响的范围 毕竟Engineer类不应该为新增的 钟点工 来买单 对象是什么 从概念层面讲 对象是某种责任的抽象 从规格层面讲 对象是一系列可以被其他对象使用的接口 API 从语言实现层面来看 对象封装了代码和数据 行为和状态 有了这些认识之后 怎样才能设计 好的面向对象 遵循一定的面向对象设计原则 熟悉一些经典的面向对象设计模式 面向对象设计原则 针对接口编程 而不是针对实现编程 客户无需知道所使用对象的特定类型 只需知道对象拥有客户所期望的接口有限使用组合 而不是类继承 类继承通常为 白箱复用 对象组合通常成为 黑箱复用 继承在某种程度上破坏了封装性 子类父类耦合度高 而对象组合则只要求被组合对象具有良好定义的接口 耦合度低 封装变化点 使用封装来创建对象之间的分界层 让设计者可以在分界层的一侧进行修改 而不会对另一侧产生不良的影响 从而实现层次间的松耦合 具体的设计原则 单一职责原则 SRP 开放封闭原则 OCP Liskov替换原则 LSP 依赖倒置原则 DIP 接口隔离原则 ISP 单一职责原则 就一个类而言应该仅有一个引起它变化的原因 当需求变化时 该变化就会反映为类的职责变化 如果一个类承担了多个职责 那么引起它变化的原因就有多个 如果一个类承担的职责过多 就等于把这些职责耦合在了一起 一个职责的变化就可能会削弱 或者抑制这个类完成其他职责的能力 如果需求变化总是引起多个职责同时变化 那么我们就不必分离它们推论 只有变化实际发生时才有意义 开放封闭原则OCP 软件实体 类 模块 函数等等 应该是可以扩展的 但是不可以修改的 对扩展是开放的 当需求变化时 我们可以对模块进行扩展 使其具有能够满足那些变化的行为 对更改是封闭的 对模块进行修改时不必改动模块的源代码 并非绝对 但是应该是最小限度 例子 InterfaceShape publicvoiddraw classSquareextendsShape publicvoiddraw classCircleextendsShape publicvoiddraw classTest publicstaticvoidmain String args Listshapes 绘制所有图形Iteratoriter shapes iterator while iter hasNext Shape iter next draw 如果要绘制一个新的形状 只需要增加一个新的Shape的派生类就行了 系统的其他地方会有一些改动 但是这里没有改动 我说谎了 上面的例子并不是100 封闭的 如果我们要求所有的圆必须在正方形之前绘制 我们就要改动Test的代码了 一般而言 无论模块多么 封闭 都会存在一些无法对之封闭的变化 没有对所有情况都贴切的模型 如何对待 设计人员必须对于他设计的模块应对哪种变化封闭做出选择 必须先猜测出最有可能发生变化的种类 然后构造抽象来隔离那些变化 有时不容易做到 代价有时会比较高 我们希望把OCP应用限定在可能发生的变化上 结论 开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象 拒绝不成熟的抽象和抽象本身一样重要 对变化进行封装 Liskov 里氏 替换原则 LSP 子类型必须能够替换掉它们的基类型 一个微妙的违规 正方形是矩形 is a关系 正方形继承矩形 publicclassRectangle privatedoubleh privatedoublew publicvoidsetHeight doubleh this h h publicvoidsetWidth doublew this w w publicdoublegetHeight returnthis h publicdoublegetWidth returnthis w publicdoublearea returnthis getHeight this getWidth publicclassSquareextendsRectangle privatedoubleh privatedoublew publicvoidsetHeight doubleh this h h this w h publicvoidsetWidth doublew this w w this h w publicdoublegetHeight returnthis h publicdoublegetWidth returnthis w publicclassTest publicvoidfun Rectangler r setHeight 1 r setWidth 2 System out println r area publicstaticvoidmain String args Rectangler newRectangle Rectangles newSquare Testt newTest t fun r t fun s 如果fun方法的参数Rectangle指向的是一个正方形 产生的结果就会让人产生迷惑 结果是4 对于写fun方法的人来讲 他会认为应该是2 IS A是关于行为的 Square对象的行为方式和函数fun所期望的Rectangle对象的行为方式不相容 对象的行为方式才是软件真正所关注的问题 关心是不是想象中的那种行为 OOD中IS A关系是就行为方式而言的 接受缺陷 大多数情况下 接受一个多态行为中的微妙错误会比试着修改设计使之完全符合LSP更为有利 接受缺陷而不是去追求完美是一个工程上权衡的问题 好的工程师知道如何接受缺陷比追求完美更有利不过 不应该轻易放弃LSP原则 我们经常用的例子struts 类RequestProcessor里面的代码 protectedActionForwardprocessActionPerform HttpServletRequestrequest HttpServletResponseresponse Actionaction ActionFormform ActionMappingmapping throwsIOException ServletException try return action execute mapping form request response catch Exceptione return processException request response e form mapping 注意红色部分 依赖倒置原则DIP 要依赖于抽象不要依赖于具体抽象不应该依赖于细节 细节应该依赖于抽象另一种说法 要对接口编程 不要针对实现编程 另一种说法的解释 应当使用java接口和抽象java类进行变量的类型声明 参量的类型声明 方法的返回类型声明 以及数据类型的转换等 Vectoremployees newVector 应该声明为Listemployees newVector 好处是 将Vector类型转会为ArrayList需要最小的改动 怎样做到 以抽象方式耦合是依赖倒转原则的关键 一个抽象耦合关系总要涉及具体类从抽象类继承 并且保证任何引用到基类的地方都可以换成其子类 因此里氏替换原则是依赖倒置原则的基础 并非完美 抽象层次上的耦合虽然有灵活性 但也带来了额外的复杂性 如果一个具体类发生变化的可能性非常小 那么抽象耦合发挥的好处便十分有限 这时使用具体耦合反而会更好 接口隔离原则ISP 接口的污染 一个没有经验的设计师往往想节省接口的数目 将几个功能相近或功能相关
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 广东管理学原理中级自考试题及答案
- 了解中医考试题及答案
- 广东法律自考试题及答案
- 控制原理考试题及答案
- 客舱清洁考试题及答案
- 铝电解综合工主管竞选考核试卷及答案
- 带式球团焙烧工入职考核试卷及答案
- 中药合剂工专项考核试卷及答案
- 押题宝典教师招聘之《小学教师招聘》通关考试题库1套附答案详解
- 钽钠还原火法冶炼工理论知识考核试卷及答案
- 友善主题班会课件
- 自动喷灌设计说明及安装大样
- 杭州市“教坛新秀”理论考试简答题汇总
- 2018年全国成人高考专升本政治试题答案
- 人教版(2019)必修三 Unit 3 Diverse Cultures Listening and Talking课件
- 医养结合机构服务质量评价标准(二级医养结合机构)
- 三年级上册数学课件-4.2 两、三位数除以一位数的笔算丨苏教版 (共34张PPT)
- 卡西欧PRO-TREK-PRW-6000使用手册-基础操作
- 建筑结构试验知识点总结
- 2022年公路工程竣交工验收办法实施细则范文
- 日本川崎市武藏小杉格林木(GrandTree)创新型购物中心调研分析报告课件
评论
0/150
提交评论