代码规范 : 抽象(ADT) 封装 与职责(2)

来源:互联网 发布:送女生礼物排行榜 知乎 编辑:程序博客网 时间:2024/06/03 11:41

根据 代码规范 : 抽象(ADT) 封装与职责(1)
的基础上,我们来看看在 程序中 , 接口, 类 , 继承, 函数 的设计

3.接口(类的抽象)

  • 类的接口应该展现一样的抽象层次:
    一个类仅只能实现同个级别接口(除了序列化和包裹化之外).如果某个类实现了多个抽象层次,那么应该把类组织成另一个抽象或多个抽象. 不要让抽象层次变得难以理解

  • 一定要理解类所实现的抽象是什么:为了在实现时选择正确

  • 提供成对的服务
    大多数操作都有和其相对应的,相等,或者相反的操作.
    例如: 会有添加(add)就会有删除(remove)的功能 前面文章中的[堆栈词表],指出了大量的这样成对的概念出现(http://blog.csdn.net/qq_22555107/article/details/78852722)
    在设计一个类的时候,要检查每一个公用的子程序,决定看是否需要另一与其互补的操作,不要盲目创建相反操作

  • 把不相关的信息移到其他类中

  • 尽可能让接口可编程,而不是表达语义
    每个接口都由一个可编程的部分和一个语义部分组成

  • 谨防在修改时破坏接口抽象

  • 不要添加与接口抽象不一致的公共成员
    保持子程序与现有接口所提供的抽象一致.,保持抽象的完整性

  • 同时考虑抽象性和内聚性
    一个呈现出很好的抽象的类接口通常也有很高的内聚性,而很强内聚性的类往往也会呈现为很好的抽象

  • 尽可能的限制类和成员的可访问性

    • 1.不要公开暴露成员的数据
    • 2.避免把私用的实现细节暴露,或放在接口里
    • 3.不要对类的使用者作出任何的假设:只要做好现在需要的做的事情, 多想无益
    • 4.避免使用友元类 friend class: 因为这样会破坏封装
    • 5.不要因为只有一个子程序里仅使用公用子程序,就把它归入公开接口
    • 6.让阅读代码比编写代码更方便
    • 7.要格外警惕从语义上破坏封装性:不要做多余的事情
  • 留意过于紧密的耦合关系:


4.类

创建类的原因

  • 1.为现实世界中的对象建模
  • 2.为抽象的对象建模
  • 3.降低复杂度:隐藏实现细节:当我使用类的对象时,我只需要知道类的表达,而不是如何表达
  • 4.隔离复杂度,限制变动的影响范围: 当引发错误时,定位到错误的地方比较容易
  • 5.隐藏全局数据:需要用到全局数据时,看把它的实现细节隐藏到某个类的接口背后,与直接使用全局数据相比,通过访问器子程序来控制全局数据时
  • 6.可以改变数据结构而无须修改程序本身
  • 7.可以见识这些数据的访问
  • 8.让参数传递更顺畅
  • 9.建立中心控制点
  • 10.让代码更容易重用
  • 11.为程序族做计划:构建整个家族的体系,你能更好的表达类在整个程序中的职责
  • 12.把相关操作包装到一起:相关操作组合到一起.可以用包,命名空间,或者头文件等方法
  • 13.实现某种特定的重构

应该避免的类

  • 1.避免创建万能的类
  • 2.消除无关紧要的类:手段,把某个类降级
  • 3.避免用动词命名的类:只有行为而没有数据的类往往不是一个真正的类, 类必须是描述一个完整的对象

5.继承

继承 (is a 关系): 继承是为了写出更加精简的代码

  • 如果派生类不准备完全遵守由基类定义的同一个接口的契约,继承就是不正确的实现技术,那么请考虑用包含的方式实现
  • 如果没有详细的说明继承,就不要去用它, 使用final 设置为不能被继承
  • 遵守Liskov 替换原则,对于基类中定义的子程序,在用它的任何一个派生类中的含义都必须相同,我们要使用Account这个基类的派生类,只要遵守Liskov 原则,这样会大大减低了程序的复杂度;相等,如果程序员在使用Accout时要考虑使用CheckingAccount还是 Savingccount 时,这样就不遵守了
  • 确保只继承需要继承的部分:
  • 不要”覆盖” 不可覆盖的成员函数:基类的函数如果定义了,子类就不要对其进行重载
  • 将公共用到的接口,数据和操作,放到尽可能高的位置: 界限在于,如果你把一个子程序放到跟高的位置会破坏该层对象的抽象性时,就要停了
  • 除了单例模式之外,一个类如只出现一个实例,那是值得怀疑的
  • 只有一个派生类的基类也值得怀疑,bean除外
  • 派生之后覆盖了某个子程序,但是没有对其进行操作,也值得怀疑
  • 避免让继承的体系过深(有的提倡是 6层,作者是提倡 3层)
  • 让内部使用的数据是的继承于 private
  • switch 用继承解决

多重继承
多重继承用于混合体,比如 Disable(可显示) ,Serializable(序列化),这种就要使用多继承,其他最好不要

何时用继承,何时用包含:

  • 如果多个类共享数据 而非行为,就可以包好公用的对象(包含)
  • 如果多个类共享行为 而非数据,就应该让他们从共同的基类继承而来,并在基类里定义共用的子程序
  • 如果多个类既共享数据也共享行为,就应该让他们从同一个共同的基类继承而来,并在基类里定义共用的数据和子程序

6.函数

1. 成员函数和数据成员

  • 让类中子程序的数量尽可能少,越多越容易出错
  • 禁止隐式的产生你不需要的成员函数和运算符
  • 减少类所哟调用的不同子程序的数量,用到其他类的程序,出错率会升高
  • 对其他类的子程序的间接调用要尽可能少
  • Demoter: A类可以调用自己的所有子程序, 创建了B对象,可以用B对象的任何(公用的)子程序, 但不能使用B对象中实例的C对象的子程序

2. 构造函数:

  • 如果可能,应该在所有的构造函数中初始化所有的数据程序
  • 用私用构造函数来强制实现单件属性(单例)
  • 优先考虑深层拷贝,除非是论证可行,采用浅层拷贝
  • 有的人是推荐构造函数不要对数据进行一个初始化,而是在类内部创建一个函数init 用来进行初始化数据

7.超越类:包

  • 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可

  • 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。

  • 类成员与方法访问控制从严:

    1) 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
    2) 工具类不允许有 public 或 default 构造方法。
    3) 类非 static 成员变量并且与子类共享,必须是 protected。
    4) 类非 static 成员变量并且仅在本类使用,必须是 private。
    5) 类 static 成员变量如果仅在本类使用,必须是 private。
    6) 若是 static 成员变量,必须考虑是否为 final。
    7) 类成员方法只供类内部调用,必须是 private。
    8) 类成员方法只对继承类公开,那么限制为 protected

原创粉丝点击