面向对象设计原则ppt课件

上传人:资****亨 文档编号:130390054 上传时间:2020-04-27 格式:PPT 页数:37 大小:261KB
返回 下载 相关 举报
面向对象设计原则ppt课件_第1页
第1页 / 共37页
面向对象设计原则ppt课件_第2页
第2页 / 共37页
面向对象设计原则ppt课件_第3页
第3页 / 共37页
面向对象设计原则ppt课件_第4页
第4页 / 共37页
面向对象设计原则ppt课件_第5页
第5页 / 共37页
点击查看更多>>
资源描述

《面向对象设计原则ppt课件》由会员分享,可在线阅读,更多相关《面向对象设计原则ppt课件(37页珍藏版)》请在金锄头文库上搜索。

1、面向对象设计原则 宋俊杰 目标 重新认识一下面向对象了解面向对象设计原则 重新认识面向对象 通过面向对象编程语言 OOPL 认识到的面向对象 并不是面向对象的全部 甚至只是浅陋的面向对象不是使用了面向对象语言就是实现了面向对象的设计和开发我们不能依赖编程语言的面向对象机制来掌握面向对象OOPL的三大机制 封装 继承 多态 可以表达面向对象的概念 但是没有刻画出面向对象的核心精神 可以用这三大机制做出好的 面向对象设计 也可以做出差的 面向对象的设计 重新认识面向对象 OOPL没有回答面向对象的根本性问题 我们为什么要面向对象 我们应该怎样实现好的面向对象 我们应该遵循什么样的原则 任何一个严肃

2、的面向对象程序员都要系统的学习面向对象知识 单纯从编程语言上获得的面向对象知识 不能够胜任面向对象设计与开发 举一个例子 示例场景 我们需要设计一个人事管理系统 其中的一个功能是对各种不同的类型员工 计算其当月的工资 不同类型的员工 拥有不同的薪金计算制度 机构化做法1 获得人事系统中所有可能的员工类型2 根据不同的员工类型所对应的不同薪金制度 计算其工资 enumEmployeeType Engineer Sales Manager 计算工资程序If type EmployeeType Enginner elseif type EmployeeType Sales 面向对象设计 1根据不同员

3、工设计不同的类 并使这些类继承自一个Employee抽象类 其中有一个抽象方法getSalary 2在各个不同的员工中 根据自己的薪金制度 重写 override getSalary方法 abstractclassEmployee publicabstractintgetSalary classSalesextendsEmployee publicintgetSalary classEngineerextendsEmployee publicintgetSalary 显示工资程序Employeee emFactory getEmployee id System out println e ge

4、tSalary 现在需求变了 示例场景 随着业务的规模的拓展 又出现了更多类型的员工 比如钟点工 计件工 等等 这对系统提出了新的挑战 原有的程序要改变 结构化做法 几乎所有涉及到员工类型的地方都要做改变 这些代码都要重新编译重新部署 面向对象做法 只要添加新的员工类 让其继承自Employee抽象方法 并重写getSalary 方法 然后在EmployeeFactory getEmployee 方法中根据相关条件产生新的员工类型就可以了 其他地方不需要改变 重新认识 对于前面的例子 从宏观上看 面向对象的构建方式跟更能适应软件的变化 能将变化所带来的影响减小到最小 从微观层面来看 面向对象的

5、方式更强调各个类的 责任 新增员工类型不会影响原来员工类型的实现代码 这是符合真实世界的 也更能控制变化所影响的范围 毕竟Engineer类不应该为新增的 钟点工 来买单 对象是什么 从概念层面讲 对象是某种责任的抽象 从规格层面讲 对象是一系列可以被其他对象使用的接口 API 从语言实现层面来看 对象封装了代码和数据 行为和状态 有了这些认识之后 怎样才能设计 好的面向对象 遵循一定的面向对象设计原则 熟悉一些经典的面向对象设计模式 面向对象设计原则 针对接口编程 而不是针对实现编程 客户无需知道所使用对象的特定类型 只需知道对象拥有客户所期望的接口有限使用组合 而不是类继承 类继承通常为

6、白箱复用 对象组合通常成为 黑箱复用 继承在某种程度上破坏了封装性 子类父类耦合度高 而对象组合则只要求被组合对象具有良好定义的接口 耦合度低 封装变化点 使用封装来创建对象之间的分界层 让设计者可以在分界层的一侧进行修改 而不会对另一侧产生不良的影响 从而实现层次间的松耦合 具体的设计原则 单一职责原则 SRP 开放封闭原则 OCP Liskov替换原则 LSP 依赖倒置原则 DIP 接口隔离原则 ISP 单一职责原则 就一个类而言应该仅有一个引起它变化的原因 当需求变化时 该变化就会反映为类的职责变化 如果一个类承担了多个职责 那么引起它变化的原因就有多个 如果一个类承担的职责过多 就等于

7、把这些职责耦合在了一起 一个职责的变化就可能会削弱 或者抑制这个类完成其他职责的能力 如果需求变化总是引起多个职责同时变化 那么我们就不必分离它们推论 只有变化实际发生时才有意义 开放封闭原则OCP 软件实体 类 模块 函数等等 应该是可以扩展的 但是不可以修改的 对扩展是开放的 当需求变化时 我们可以对模块进行扩展 使其具有能够满足那些变化的行为 对更改是封闭的 对模块进行修改时不必改动模块的源代码 并非绝对 但是应该是最小限度 例子 InterfaceShape publicvoiddraw classSquareextendsShape publicvoiddraw classCircl

8、eextendsShape publicvoiddraw classTest publicstaticvoidmain String args Listshapes 绘制所有图形Iteratoriter shapes iterator while iter hasNext Shape iter next draw 如果要绘制一个新的形状 只需要增加一个新的Shape的派生类就行了 系统的其他地方会有一些改动 但是这里没有改动 我说谎了 上面的例子并不是100 封闭的 如果我们要求所有的圆必须在正方形之前绘制 我们就要改动Test的代码了 一般而言 无论模块多么 封闭 都会存在一些无法对之封闭的

9、变化 没有对所有情况都贴切的模型 如何对待 设计人员必须对于他设计的模块应对哪种变化封闭做出选择 必须先猜测出最有可能发生变化的种类 然后构造抽象来隔离那些变化 有时不容易做到 代价有时会比较高 我们希望把OCP应用限定在可能发生的变化上 结论 开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象 拒绝不成熟的抽象和抽象本身一样重要 对变化进行封装 Liskov 里氏 替换原则 LSP 子类型必须能够替换掉它们的基类型 一个微妙的违规 正方形是矩形 is a关系 正方形继承矩形 publicclassRectangle privatedoubleh privatedoublew publi

10、cvoidsetHeight 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 p

11、ublicvoidsetWidth 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

12、 fun r t fun s 如果fun方法的参数Rectangle指向的是一个正方形 产生的结果就会让人产生迷惑 结果是4 对于写fun方法的人来讲 他会认为应该是2 IS A是关于行为的 Square对象的行为方式和函数fun所期望的Rectangle对象的行为方式不相容 对象的行为方式才是软件真正所关注的问题 关心是不是想象中的那种行为 OOD中IS A关系是就行为方式而言的 接受缺陷 大多数情况下 接受一个多态行为中的微妙错误会比试着修改设计使之完全符合LSP更为有利 接受缺陷而不是去追求完美是一个工程上权衡的问题 好的工程师知道如何接受缺陷比追求完美更有利不过 不应该轻易放弃LSP原

13、则 我们经常用的例子struts 类RequestProcessor里面的代码 protectedActionForwardprocessActionPerform HttpServletRequestrequest HttpServletResponseresponse Actionaction ActionFormform ActionMappingmapping throwsIOException ServletException try return action execute mapping form request response catch Exceptione return

14、 processException request response e form mapping 注意红色部分 依赖倒置原则DIP 要依赖于抽象不要依赖于具体抽象不应该依赖于细节 细节应该依赖于抽象另一种说法 要对接口编程 不要针对实现编程 另一种说法的解释 应当使用java接口和抽象java类进行变量的类型声明 参量的类型声明 方法的返回类型声明 以及数据类型的转换等 Vectoremployees newVector 应该声明为Listemployees newVector 好处是 将Vector类型转会为ArrayList需要最小的改动 怎样做到 以抽象方式耦合是依赖倒转原则的关键 一

15、个抽象耦合关系总要涉及具体类从抽象类继承 并且保证任何引用到基类的地方都可以换成其子类 因此里氏替换原则是依赖倒置原则的基础 并非完美 抽象层次上的耦合虽然有灵活性 但也带来了额外的复杂性 如果一个具体类发生变化的可能性非常小 那么抽象耦合发挥的好处便十分有限 这时使用具体耦合反而会更好 接口隔离原则ISP 接口的污染 一个没有经验的设计师往往想节省接口的数目 将几个功能相近或功能相关的接口合并 并将这看成是代码优化的一部分 接口隔离原则ISP 定义 从一个客户类的角度来讲 一个类对另外一个类的依赖性应当是建立在最小接口上的 使用多个专门的接口比使用单一的总接口要好 例子 例子 单一职责 总结 开 闭 原则 OCP 对可变性封装里氏替换原则 LSP 如何进行继承依赖倒置原则 DIP 针对接口编程接口隔离原则 ISP 恰当的划分接口和角色 我所理解的好软件 满足需求能够应对变化 结束 谢谢 我所理解的好软件 满足需求能够应对变化 结束 谢谢

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号