《软件构造》 第五章 基于可复用性的软件构造处理
》》可复用性
高复用性的软件应具有如下特性:小、简单;与标准兼容;灵活可变;可扩展;泛型、参数化;模块化;变化的局部性;稳定;丰富的文档和帮助
白盒复用:源代码可见,可修改和扩展。复杂度高,需要对内部代码充分了解
黑盒复用:源代码不可见,无法修改代码;简单清晰,适应性差
可复用性外部观察:
——类型可变:能够复用的部分应该类型参数化,以适应不同的数据类型;复用的部分应该一般化;适应不同的类型,且满足LSP(子类一定可以替代父类)
——实现可变:ADT 有多种不同的实现,提供不同的representations 和abstract function ,但具有同样的specification (pre-condition, post-condition, invariants) ,从而可以适应不同的应用场景
——功能分组:提供完备的细粒度操作,保证功能的完整性,不同场景下复用不同的操作( 及其组合)
——表示独立:内部实现可能会经常变化,但客户端不应受到影响。
——共性抽取:将共同的行为(共性)抽象出来,形成可复用实体
LSP:更强的不变量;前置条件更弱;后置条件更强
协变:父类型->子类型:越来越具体specific 返回值类型:不变或变得更具体;异常的类型:也是如此。
反协变、逆变:父类型->子类型:越来越具体specific 参数类型:要相反的变化,要不变或越来越抽象(在java中不允许)
数组的子类型化:
——数组是协变的:一个数组T[ ] ,可能包含了T类型的实例或者T的任何子类型的实例
——即子类型的数组可以赋予父类型的数组进行使用,但数组的类型实际为子类型。
——下面报错的原因是myNumber指向的还是一个Integer[] 而不是Number[]
Number[] numbers = new Number[2]; numbers[0] = new Integer(10); numbers[1] = new Double(3.14); Integer[] myInts = {1,2,3,4}; Number[] myNumber = myInts; myNumber[0] = 3.14; //run-time error!泛型的子类型化:
泛型的类型是不变的:ArrayList<String> is a subtype of List<String>; List<String> is not a subtype of List<Object>
通配符:? 表示所有满足条件的未知类型 List<Number> is a subtype of List<?>
List<Number> is a subtype of List<? extends Object>
List<Object> is a subtype of List<? super String>
委派和组合:
比较器(Comparator):
另一种方法:让你的ADT实现
Comparable接口,然后
override compareTo()方法。与使用
Comparator的区别:不需要构建新的
Comparator类,比较代码放在ADT内部。下面为具体例子。
委派(delegation):在一个类中调用另一个类的方法
——显性委派:将发送对象传递给接收对象。
——隐性委派:由语言的成员查找规则。
可以看到,想在B中调用A,需要先委派一个A
CRP(合成复用原则):委派可以看做Object层面的复用机制,而继承可以看做是类的层面
在委派时多使用接口,实例化接口然后重写接口的方法
委派的种类:
——临时性委派(Dependency):最简单的方法,调用类里的方法(use a),其中一个类使用另一个类而不实际地将其作为属性。
——永久性委派(Association):类之中有其它类的具体实例来作为一个变量(has a)。
——更强的委派,组合(Composition):更强的委派。将一些简单的对象组合成一个更为复杂的对象。(is part of)。里面其中一个对象损坏,则组合对象损坏
——聚合(Aggregation):对象是在类的外部生成的,然后作为一个参数传入到类的内部构造器。(has a)
可复用的库和框架:
白盒框架和黑盒框架:白盒一般是继承,黑盒一般是委派、组合
——白盒框架是基于面向对象的继承机制。之所以说是白盒框架,是因为在这种框架中,父类的方法对子类而言是可见的。子类可以通过继承或重写父类的方法来实现更具体的方法。虽然层次结构比较清晰,但是这种方式也有其局限性,父类中的方法子类一定拥有,要么继承,要么重写,不可能存在子类中不存在的方法而在父类中存在。
public abstract class PrintOnScreen { public void print() { JFrame frame = new JFrame(); JOptionPane.showMessageDialog(frame, textToShow()); frame.dispose(); } protected abstract String textToShow(); }
public class MyApplication extends PrintOnScreen { @Override protected String textToShow() { return "printing this text on " + "screen using PrintOnScreen " + "white Box Framework"; } }——黑盒框架时基于委派的组合方式,是不同对象之间的组合。之所以是黑盒,是因为不用去管对象中的方法是如何实现的,只需关心对象上拥有的方法。这种方式较白盒框架更为灵活,因为可以在运行时动态地传入不同对象,实现不同对象间的动态组合;而继承机制在静态编译时就已经确定好。黑盒框架和白盒框架可以互相转化。
public interface TextToShow { String text(); }
public class MyTextToShow implements TextToShow { @Override public String text() { return "Printing"; } }
public final class PrintOnScreen { TextToShow textToShow; public PrintOnScreen(TextToShow tx) { this.textToShow = tx; } public void print() { JFrame frame = new JFrame(); JOptionPane.showMessageDialog(frame, textToShow.text()); frame.dispose(); } }》》复用的设计模式
——结构型模式:Structural patterns
适配器模式(Adapter)
装饰器模式(Decorator )
外观模式(Facade)
——行为类模式:Behavioral patterns
策略模式(Strategy)
模板方法模式(Template method)
迭代器模式( Iterator)
适配器模式:将某个类或接口转换为用户期望的其他形式
实例:问题描述:其中LegacyRectangle是已有的类(需要传入矩形的一个顶点、长和宽),但是与client要求的接口不一致(需要给出对角线两个顶点坐标),我们此时建立一个新的接口Shape以供客户端调用,用户通过Shape接口传入两个点的坐标。Rectangle作为Adapter,实现该抽象接口,通过具体的方法实现适配。 在不适用适配器时:会发生委派不相容。
装饰器模式:为对象增加不同侧面的特性,对每一个特性构造子类,通过委派增加到对象上
Stack s = new ArrayStack(); //构建一个普通的堆栈
UndoStack s = new UndoStack(new ArrayStack()); //构建撤消堆栈
SecureStack s = new SecureStack( new SynchronizedStack( new UndoStack(s)))//构建安全的同步撤消堆栈
外观模式:客户通过一个简化的接口来访问复杂系统内的功能。把多种相似类型的类及其功能用一个类封装起来,通过传参在内部完成选择
客户端代码
策略模式:一个类的行为或算法可以在运行时更改。针对特定任务存在不同的算法,但客户端可以根据动态上下文在运行时切换算法。就是在一个接口下设计多个子类,每个子类有自己的功能算法。在运行时调用接口的不同子类实现不同选择。
模板模式:模板模式中,一个抽象类公开定义了执行它的方法的方式/模式,它的子类可以按照需要重写实现方法,但调用将以抽象类中定义的方法进行。
例子,对于边的定义时,无向边,有向边只需要重写边的方法,或者再增加一些方法。
迭代器模式:这种模式用于顺序访问集合对象的元素,而又无需暴露该对象的内部表示。用途:解决客户需要统一的策略来访问容器中的所有元素,与容器类型无关。实现方法:这种模式让自己的集合类实现Iterator接口,并实现自己的独特
Iterator迭代器(
hasNext, next, remove),允许客户端利用这 个迭代器进行显式或隐式的迭代遍历
例子:
- 软件构造系列之可复用性的构造(2)——如何构造之子类型多态和委托部分
- 3DGIS第五章 基于GPU的优化处理
- 基于MFC和OpenCV的图像处理小软件
- 基于命令行的mahout软件0.8版本Canopy算法分析的数据处理流程
- Linux平台下基于BitTorrent应用层协议的下载软件开发--消息处理模块(message.h)
- 软件构造系列之可维护性的构造——基于语法的讨论
- 《软件构造》 第七章 软件构造的健壮性
- 基于MFC和OpenCV的图像处理小软件(续)
- .net企业应用高级编程 第五章 自动化处理和事务处理(基于C# XML)案例
- 软件构造 异常处理的5个建议
- 基于mfc数字图像处理的小软件pdd-量化灰度图像
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 处理报表
- 第五章 基于GPU的优化处理
- 基于mfc数字图像处理的小软件pdd-改变图片的大小
- 基于WWW构造桌面软件-胡思乱想
- IOS 构造和使用TableView(基于storyboard) (二)接收和处理Table View事件
- 软件构造系列之可复用性的构造(1)——关于软件的可复用性基本概念理解
- Linux平台下基于BitTorrent应用层协议的下载软件开发--出错处理模块(bterror.c)
- 软件构造系列学习笔记(1.2)————软件构造的质量目标
- 基于Android的图像处理演示软件介绍文档