面向对象编程与面向对象分析
面向对象编程不是使用面向对象的编程语言进行编程,而是利用多态特性进行编程。
面向对象分析是将客观世界,即编程的业务领域进行对象分析。
面向对象设计的目的和原则
软件设计的最终目的,是使软件达到「强内聚、松耦合」,从而使软件:
-
易扩展-易于增加新的功能 -
更强壮-不容易被粗心的程序员破坏 -
可移植-能够在多样的环境下运行 -
更简单-容易理解、容易维护
面向对象设计的原则
设计模式
设计模式是用于解决某一种问题的通用的解决方案。设计模式也是语言中立的。设计模式贯彻了设计原则。
框架(frameworks)
框架是用来实现某一类应用的结构性的程序,是对某一类架构方案可复用的设计与实现
不同领域的框架
框架 VS 工具
框架调用应用程序代码 应用程序代码调用工具
架构师框架保证架构的落地 架构师用工具提高开发效率
软件设计的「臭味」
不好的软件,会发出如下臭味
-
僵硬-不易改变 -
【僵化性】如果单一的改动会导致依赖关系的模块中的连锁改动,那么设计就是僵化的,必须要改动的模块越多,设计就越僵化。 -
脆弱-只想改A,结果 B 被意外破坏 -
【脆弱性】如果出现新问题的地方与改动的地方没有概念上的关联。要修正这些问题又会引出更多的问题,从而使开发团队就像一只不停追逐自己尾巴的狗一样。 -
不可移植-不能适应环境的变化 -
【牢固性】设计中包含了对其他系统有用的部分,而把这些部分从系统中分离出来所需要的努力和风险是巨大的。 -
导致误用的陷阱-做错误的事比做正确的事更容易,引诱程序员破坏原有的设计 -
【粘滞性】可以保持系统设计的方法比破坏设计的方法更难应用时。 -
晦涩-代码难以理解 -
【晦涩性】没有很好的表现出意图 -
过度设计、copy-paste 代码 -
【不必要的复杂与重复】
OOD 原则一:开闭原则(OCP)
OCP-OPEN/Closed Principle
传统的扩展模块的方式就是修改模块的源代码。如何实现不修改而扩展呢?
Phone-Dialer-digitButtons-sendButton【观察者模式】
OOD 原则二:依赖倒置原则(DIP)
DIP - Dependency Inversion Principle
-
高层模块不能依赖低层模块,而是大家都依赖抽象; -
抽象不能依赖实现,而是依赖抽象。
DIP 倒置了什么?
软件的层次化
框架的核心
好莱坞规则:
- Don’t call me,I’ll call you.
程序不要调用框架,框架来调用应用程序。【依赖倒置:你想用框架,但不用去调用框架(spring,Junit,Tomcat)】
OOD 原则三:Liskov 替换原则(LSP)
在 Java/C++ 这样的静态类型语言中,实现 OCP 的关键在于抽象,而抽象的威力在于多态和继承。
-
一个正确的继承要符合什么要求呢? -
答案:Liskov 替换原则
1988 年 Liskov 描述这个原则:
错误示范 【使用基类的地方,不能用子类代替】
从契约的角度看 ?LSP
-
LSP 要求,凡是使用基类的地方,一定也适用于其子类。 -
Java 语法上看,意味着: -
子类一定得拥有基类的整个接口。 -
子类的访问控制不能比基类更严格。 -
子类的契约不能比基类更严格 -
例如,正方形长度相等,这个契约比长方形要严格,因此正方形不是长方形的子类 -
例如,Properties 的契约比 Hashtbale 更严格。
如何重构代码,以解决 LSP 问题
-
提取共性到基类; -
改成组合
继承 VS 组合
继承和组合是 OOP 的两种扩展手段。
继承的优点:
- 比较容易,因为基类的大部分功能都可以通过继承直接进入子类。
继承的缺点:
-
破坏封装,将基类细节暴露给子类,继承是白盒复用 -
基类改变,影响子类 -
继承是静态的,无法在运行时改变组合 -
类数量爆炸
应该优先使用组合
OOD 原则四:单一职责原则(SRP)
SRP - Single Responsibility Principle
什么是职责?
-
单纯谈论,定义不同 -
定义:一个职责是一个变化的原因。
违反 SRP 原则的后果
后果:
OOD 原则五:接口分离原则(ISP)
ISP- interface Segregation Principle
ISP 和 SRP 的关系:
推荐书:敏捷软件开发
|