[关闭]
@zhongjianxin 2017-09-26T12:17:44.000000Z 字数 4421 阅读 1195

OO-Bootcamp

TWSchool-Courses


OO的一些关注点

  1. 可见性(Public)
  2. Equal vs Same
  3. ValueObject VS ReferObject
  4. Exception VS ErrorCode
  5. immutability

面向对象的S.O.L.I.D 原则

  1. Single Responsibility Principle (SRP) – 职责单一原则
  2. Open/Closed Principle (OCP) – 开闭原则
  3. Liskov substitution principle (LSP) – 里氏代换原则
  4. Interface Segregation Principle (ISP) – 接口隔离原则
  5. Dependency Inversion Principle (DIP) – 依赖倒置原则

其他编程或设计原则

  1. Don’t Repeat Yourself (DRY)
  2. Keep It Simple, Stupid (KISS)
  3. Composition over inheritance(喜欢组合而不是继承)
  4. Command-Query Separation (CQS) – 命令-查询分离原则
  5. You Aren’t Going to Need It (YAGNI) 只考虑和设计必须的功能,避免过度设计。
  6. Law of Demeter – 迪米特法则,最少知识原则
  7. Hollywood Principle – 好莱坞原则
  8. High Cohesion & Low/Loose coupling & – 高内聚, 低耦合
  9. Convention over Configuration(CoC)– 惯例优于配置原则
  10. Separation of Concerns (SoC) – 关注点分离
  11. Design by Contract (DbC) – 契约式设技

职责分配原则

基于职责设计对象(GRASP):General Responsibility Assignment Software Pattern
类的职责是类的契约和义务,包括行为职责(初始化其他对象、控制和协调其他对象的活动)和认知职责(对私有封装数据的认知、对其他对象的认知、对其能够导出或计算出的对象的认知)。GRASP是关于对象设计和职责分配的一组基本原则,有以下原则:
1. 创建者:如果以下条件之一(越多越好)为真时,将创建A的职责分配给B
B包含或组成聚集A
B记录A
B直接使用A
B具有A初始化所需要的数据,并且在创建A的时候会将这些数据传递给A
基本意图是寻找在任何情况下都与被创建者有直接连接的创建者。
2. 信息专家:把职责分配给具有实现这个职责所必需信息的信息专家(分配职责从清晰买描述对象职责开始,把职责分配给具有完成此职责所需信息的对象。“知其责,行其事”)。
3. 低耦合:分配职责,使耦合性尽可能低(低耦合是制定设计决策的时候必须牢记的原则)。
4. 控制器:把职责分配给能够代表以下选择之一的对象(控制器是在UI层首先接收和协调系统操作信息的第一个对象)。
代表整个系统、跟系统、运行软件的设备或主要的子系统。这些事外观控制器的所有变体。
代表用例场景,在该场景中发生的事件通常命名为<..>Handler/Session等。这些事用例或会话控制器。
5. 高内聚:分配职责要保持较高的内聚性(高内聚:元素具有高度的相关的职责,而且没有过多的职责)。
6. 多态:当相关选择或行为随类型(类)有所不同时,使用多态操作为变化的行为分配职责。
7. 纯虚构:对认为制造的一组类分配一组高内聚的职责,该类并不代表问题域的概念—虚构的事物,用以支持高内聚、低耦合和复用。
8. 间接性:将职责分配给中介对象,使其作为其他构件或服务之间的媒体,以避免他们之间的直接耦合。
9. 防止变异:识别或预计变化或不稳定之处,分配职责用以在这些变化之处创建稳定的接口。

封装

封装 (encapsulation) 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。

  1. 封装途径
    封装就是将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
  2. 封装的目的
    是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。

思考封装 封装就是信息隐藏。 避免暴露知识点,例如用什么方式实现,就是知识点。
在这道题目里,“长度的换算,是通过计算比率实现的”,就是一个知识点,也即揭露了背后的工作原理,暴露了实现细节。 使用者应当只看到把一个长度转换成另外一个长度,而不应关心是用比率实现的,还是用其他方式来计算的。

封装:封装的意义,在于明确标识出会访问某个数据结构(用面向对象的术语来说就是 类成员变量)的所有接口。

有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明(注意:对外透明的意思是,外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在;而不是外部调用者为了完成某个功能、却被碍手碍脚的private声明弄得火冒三丈;最终只能通过怪异、复杂甚至奇葩的机制,才能更改他必须关注的细节——而且这种访问往往被实现的如此复杂,以至于稍不注意就会酿成大祸)。

异常

重构

Bad Smell

设计模式

思考:(策略 VS 继承)

  1. 通过继承的时候有可能当引入Manager的时候,因为FindLocer的逻辑与其他Robot的差别,会导致影响Findlocker的接口,产生味道,对象结构显得越来越别扭,促使转向策略模式
  2. 继承是静态结构,策略是动态组合模式,继承更加固定以及稳定,而策略则更加的灵活及不稳定。
  3. 类爆炸是由继承导向策略的一个味道
  4. 策略总是基于类型的判断,则是由策略转向继承的一个味道
  5. 如果子类不是已经存在可以直接使用的情况(每次都要new一个新的子类),需要考虑继承
  6. 参考《重构》《重构到模式》
  7. 如果组合的方式是有限且固定的,那使用组合反而不如使用继承的约束更强,表达的信息更明确,直接,简单。
  8. 如果子类复用了超类的行为(实现),却又不愿意支持超类的接口,Refused Bequest的坏味道就会变得浓烈。拒绝继承超类的实现,这一点我们不介意;但如果拒绝继承超类的接口,我们不以为然。不过即使你不愿意继承接口,也不要胡乱修改集成体系,应该运用“替换成代理”来达到目的
  9. 为判断自己到底应该选用组合还是继承,一个最简单的办法就是考虑是否需要从新类上溯造型回基础类。若必须上溯,就需要继承。但如果不需要上溯造型,就应提醒自己防止继承的滥用。但只要记住经常问自己“我真的需要上溯造型吗”,对于组合还是继承的选择就不应该是个太大的问题.
  10. http://www.cnblogs.com/wangyingtao/archive/2008/10/26/1319759.html
    开闭原则、优先使用组合,你还记得吗?
    在我们很多OO程序员的脑子里总是存在这样一个观念:没有继承的程序不是OO的程序,看到重复总是想到继承。当初我也是这样想的,有的时候看到自己画的庞大的继承类图,心里在乐呵呵的笑。可继承总是不给面子,一个小小的变化就将这个看似稳定的体系弄的支离破碎。

    还是回到我们的例子,在这个例子中变化的是各高校的报到步骤,本着发现变化、封装变化、隔离变化的原则我们将报到的步骤分离出来,独立成类。

    在本篇我们从模板方法谈起,聊了一些模板方法随着项目的发展可能造成的问题,但这并不是模板方法的弊端,模板方法关注的是算法骨架的复用,如果你发觉新的问题出现,这可能就是模板方法不再适用的信号。通过我们对项目的扩展,发现继承在某些时候并不是都能达到代码复用的目的,这个时候我们应该考虑组合了,而且继承是一种静态的编译期的行为(针对像C#这种强类型静态语言而言),代码一经写定我们就没有选择的余地了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注