代码可理解性
1.度量
- 标识符的平局长度
- 命名独特性比例
- 代码复杂度
- LoC 代码行数
- 注释密度(百分比)
2.如何书写可理解性代码
- 命名规范
- 代码行最大长度,文件最大LoC
- 注释
- 布局:缩进、对齐、空行、分块等
- 避免多层嵌套(增加复杂度)
- 文件和包的组织
3.包的相关原则
- REP 复用/发布等价原则
复用的粒度等价于发布的粒度(发布的都是应被复用的,未发布的不应被复用) - CCP Common Closure Principle 共同封闭原则
- 一个包中的所有类针对同一种变化是封闭的
- 一个包的变化将会影响到包里所有的类,而不会影响到其他的包
- 如果两个类紧密耦合在一起,即二者总是同时发生变化,那么它们应属于同一个包
- CRP Common Reuse Principle 共同复用原则
- 一个包里的类应被一起复用
- 如果复用了其中一个类,那么就应复用所有的类
总之,尽量把相关性高的类放在一起,对不同类进行合理划分。
代码复用
1.可复用组建的形态和层级
- 源代码:方法、声明等
- 模块:类、接口
- 库:API
- 系统(结构):framework 框架:一组具体类、抽象类及其之间的连接关系
2.代码复用的类型:
- White box 白盒复用:源代码可见,可修改和扩展。即,直接复制修改代码。可定制化程度高,但需要充分了解代码。
- Black box 黑盒复用:源代码不可见,不能修改
只能通过API接口使用,无法修改代码。简单、清晰,但适应性差。
3.Frameworks :domain-level reuse 领域复用
- 框架:一组具体类、抽象类及其之间的连接关系
- 开发者根据framework的规约,填充自己的代码进去,形成完整的系统;
- 开发者 增加新代码、对抽象类机型具体化、实现接口;
- Framework作为主程序加以执行,执行过程中调用开发者所写的程序。
- 控制反转(inverse of control),控制权由代码转到了外部容器(framework),好处是降低了对象之间的依赖程度,提高灵活性和可维护性。
4.External observations of reusability 可复用的外部观察特性
- Type variation 类型可变:泛型,且满足LSP
- Implementation variation 实现可变:
ADT有多种不同的实现,提供不同的representations和abstract funtion,但具有同样的specification (pre-condition, post-condition, invariants),从而可以适应不同的应用场景 - Routine grouping 功能分组:
- Representation independence 表示独立
内部实现可能会经常变化,但客户端不应受到影响(不变量为true) - Factoring out common behaviors 抽取共性行为
LSP (Liskov substitution principle) liskov 替换原则
- 子类型可以增加,但不可删除方法
- 子类型需要实现抽象类中所有未实现的方法
- 子类型中重写的方法必须有相同或子类型的返回值 co-variance:协变
- 子类型中重写的方法必须使用同样类型的参数 contra-variance 反协变(逆变)
- 子类型中重写的方法不能抛出额外的异常 协变
- 同样或更强的不变量
- 同样或更弱的前置条件
- 同样或更强的后置条件
Covariance 协变、Contravariance 反协变,逆变
关于Java的协变和逆变
Comparator and Comparator
关于Java中的集合的两种排序方法
Delegation 委派
- 一个对象请求另一个对象的功能
- 如果子类只需要复用父类中的一小部分方法,可以不需要使用继承,而是通过委派机制实现。
即,一个类不需要继承另一个类的全部方法,通过委派机制调用部分方法。 - "委派"发生在object层面,"继承"发生在class层面
1.委派的类型
Dependency 依赖
- 临时的委派 (B uses A)
类内调用 - A类是B类中的(某中方法的)局部变量;
- A类是B类方法当中的一个参数;
- A类向B类发送消息,从而影响B类发生变化;
Association 关联
- 永久的委派 (B owns A) (关联关系可以是双向的)
- A类为B的成员变量(或者对象数组)。
- 也可能自关联(如,自身的成员变量有自身的实例,如父节点有子节点)
Composition 组合 更强的委派 (A is part of B )
- A是B的一部分,B不能脱离A存在,A不能单独存在。
Aggregation 聚合
- 整体和部分(可有可无)的关系。
关于Java的UML类图的学习总结
CRP (Composite Reuse Principle)组合复用原则
- 对于某一具体行为,用委派代替继承。
- 使用接口定义不同方面的行为,
- 接口之间通过extends实现行为的组合(组合多用接口,则组合接口汇集了其他接口的行为)。
- 用具体类实现组合接口。
White box and black box framework 白盒框架和黑盒框架
白盒框架 | 黑盒框架 | |
---|---|---|
实现方式 | 通过 子类 和 重写方法 实现扩展 继承 | 通过实现 插件接口 实现扩展 委派/组合 |
常用设计模式 | 模板方法 | 策略模式 观察者模式 |
调用机制 | 子类型有main方法,但framework拥有控制权 | 插件加载机制加载插件(委派),framework拥有控制权 |
另一种实现 | 在抽象父类中添加abstract方法(需修改framework代码)子类实现abstract方法 | 实现预留接口(不需修改framework代码,framework中有预留接口)实现类实现接口 |
例如Class WhiteRun extends Thread{(override run) } New WhiteRun().strat | 例如Class BlackRun implements Runnable New Thread( new BlackRun() ).start() |
设计模式
1.Structural patterns 结构型设计模式
Adapter 适配器模式
- 将某个类/接口 转换为client期望的其他形式(client的调用传参与类/接口 方法的参数列表不一致,不兼容)
- 增加一个接口,将已存在的子类封装
- Client面向接口编程,从而隐藏具体子类。
- 适配器类实现接口或继承实现接口的父类,
- 适配器中调用子类方法实现功能(委派)。
- 可能client调用子类方式(如参数形式等)与子类不匹配,通过适配器进行调整调用,适配子类,从而实现原本不兼容的调用。
Decorator 修饰器
- 为对象增加不同侧面的特性。
- 对每一个特性构造子类,通过委派机制增加到对象上。
例如:Collections.synchronizedList( List<T> list)
即返回一个在list增加了新特性的对象。 - 为对象本身和其需要增加的特性进行封装,
- 基础功能通过委派(父类)实现,并额外增加新特性,成为一个新的类。
- Client可以通过层层修饰获得具有多种特性的对象。
Façade 外观模式
- 客户端需要通过一个简化的接口来访问复杂系统内的功能。
- 提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统进行封装,简化客户端使用。
2.Behavioral patterns 行为类设计模式
Strategy 策略模式
- 对一个任务,有多用算法实现。
- 为该任务创建一个接口,
实现类实现同一接口中的方法。
Template method 模板模式
- 做事情的步骤一样,但具体方法不同。
- 共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。
- 使用继承和重写实现模板模式。
- 模板模式广泛应用于framework。
Iterator 迭代器
- 独立于元素类型,访问容器内的所有元素。