面向复用的软件构造技术
目 录
- 复用模块的层次和形态学模式
- 复用的层面:代码层面;软件构造过程中的任何实体都可能被复用。
- 代码复用的种类:白盒复用:源代码可见,可修改和扩展;黑盒复用:源代码不可见,不能修改;
1.1源代码复用
复制/粘贴 部分/全部 到你的程序中,维护问题。
1.2模块级复用:类/接口
不需要源代码,只需要类文件或jar/zip。可以使用javap工具来获得一个类的公共方法头文件,需要将相关的类打包在一起 -- 静态链接。
inheritance继承:
delegation委托:
1.3模块级复用:库层面复用:API/Package
- 库:一组提供可重复使用功能的类和方法(API)。开发者构造可运行软件实体,其中涉及到对可复用库的调用。
- 框架:可重复使用的骨架代码,可以定制成一个应用程序。Framework作为主程序加以执行,执行过程中调用开发者所写的程序
1.4系统级的复用:框架
(1)框架:一组具体类、抽象类、及其之间的连接关系,开发者根据framework的规约,填充自己的代码进去,形成完整系统。将framework看作是更大规模的API复用,除了提供可复用的API,还将这些模块之间的关系都确定下来,形成了整体应用的领域复用。
(2)分类:框架可以按照用于扩展的技术进行分类
白盒框架,通过代码层面的继承进行框架扩展,通过继承和动态绑定实现可扩展性,通过子类化框架基类和重写预定义的钩子方法来扩展现有的功能。
黑盒框架,通过实现特定接口/delegation进行框架扩展,通过为可以插入框架的组件定义接口来实现可扩展性,通过定义符合特定接口的组件来复用现有的功能
- 设计可复用类
2.1行为子类和里氏替换原则(LSP)
- 行为子类:子类型多态:客户端可用统一的方式处理不同类型的对象。
- Liskov替换原则(LSP):
第一种定义:如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
第二种定义:所有引用基类的地方必须能透明地使用其子类的对象。
- LSP:
Covariance (协变):父类型à子类型:越来越具体specific返回值类型:不变或变得更具体,异常的类型也是如此。
Contravariance (反协变、逆变):父类型à子类型:越来越具体specific参数类型:要相反的变化,要不变或越来越抽象,目前Java中遇到这种情况,当作overload看待
(4)泛型不是协变的:编译代码完成后,编译器丢弃类型参数的类型信息;因此,此类型信息在运行时不可用。
2.2委托和组成Delegation and Composition
- Delegation委托:委派/委托:一个对象请求另一个对象的功能。例如,排序器将功能委托给一些比较器。委托可以被描述为实体之间共享代码和数据的低级机制。
- The delegation pattern委派模式:通过运行时动态绑定,实现对其他类中代码的动态复用。
- 使用委托来扩展功能
- 复合重用原则(CRP):类通过“组合”实现多态和复用(通过引入其他类的实例来实现功能)而不是通过基类或父类。
- “委托”发生在object层面,而“继承”发生在class层面
- 接口组合:
- Dependency: 临时性的delegation:仅仅是在参数中出现,调用了相应方法,甚至都没有实例化对象。
- Association: 永久性的delegation:一个类有另一个作为属性/实例变量,但彼此仍可分
- Composition: 更强的association,但难以变化:不同于一般的Association,这里变成了其一部分属性,并且彼此不可分,在内部创建。
- Aggregation: 更弱的association,可动态变化:对象存在于另一个对象之外,是在外部创建的,因此它作为参数传递给构造函数。
- 设计系统级可复用的API库和框架