HIT软件构造笔记六
一.可复用性的度量、形态与外部表现
1.可复用性的评估
评估的方面:复用的频繁性、复用的代价 (适配)
一个有高可复用性的代码应该有如下特点:小、简单;与标准兼容;灵活可变;可扩展;泛型、参数化;模块化;变化的局部性;稳定;丰富的文档和帮助。
2、复用的层面
两种复用的方式:白盒复用和黑盒复用。黑盒复用就类似于调用API接口,或者方法等等;白盒复用是直接得到想要复用的源代码(或其他内容)等等,然后自己根据需要进行修改。
根据复用内容的结构从小到大,分为如下四种复用。
(1).源代码级别的复用:这个是最底层的复用,就是简单的复制粘贴修改。
(2).模块级复用:以class作为最基本的单元,复用的方式有继承和委托,其中委托的耦合度明显低于继承。
(3).类库级重用:相当于把一系列的class进行了打包,类似于第三方库的调用。
(4).框架级复用:在框架的基础上,填充自己的代码,形成完整系统。(其实就类似于一些实验中,给出了很多代码,要求我们填入一些自己的代码)
二.面向复用的软件构造技术
1、LSP与泛型中的运用
Liskov替换原则,从实际设计的角度来说,这个原则其实就是对子类型的约束:要求子类型对象完全可以当作父类型的对象来使用,其中就包括了规约的前置条件不能强化,后置条件不能弱化,要保持不变量等等。
下面介绍协变与异变的概念。
协变:子类对父类方法的覆写中,异常、返回值的类型是父类方法中返回值的类型的子类型,就称之为协变。
逆变:顾名思义,与协变恰恰相反。
因此为了复合Liskov替换原则,我们要求如果有变化的话,那异常,返回值必须是协变,参数必须是异变(当然,在java语言中参数的异变或协变导致方法不再是覆写,而是重载)。
java中的泛型是类型不变的,如下图所示,是十分经典的例子。如果想进行协变或逆变,则需要使用通配符,例如List<? extends Number>是List < Number>的子类型,但是不论如何都要确保一个List中的元素都是一种类型的(尽管多种元素都可以放入)。
2、委托与组合
委派/委托:一个对象请求另一个对象的功能。
四种委派方式:
①Dependency:依赖关系,临时性的delegation
②Association:关联关系,永久性的delegation。
③Composition: 更强的association,但难以变化。
④Aggregation: 更弱的association,可动态变化。
组合:利用delegation的机制,将功能的具体实现与调用分离,在实现中又通过接口的继承树实现功能的不同实现方法,而在调用类中只需要创建具体的子类型然后调用即可。
3、框架framework
黑盒框架:通过实现特定接口进行框架扩展,采用的是delegation机制达到这种目的,通常采用的设计模式是策略模式(Strategy)和观察者模式(Observer)
白盒框架:通过继承和重写实现功能的扩展,通常的设计模式是模板模式(Template Method)。