从类,API,框架三个层面学习如何设计可复用软件实体的具体技术学习心得
软件复用概述
软件复用概念
软件复用(SoftWare
Reuse)是将已有软件的各种有关知识用于建立新的软件,以缩减软件开发和维护的花费。软件复用是提高软件生产力和质量的一种重要技术。早期的软件复用主要是代码级复用,被复用的知识专指程序,后来扩大到包括领域知识、开发经验、设计决定、体系结构、需求、设计、代码和文档等一切有关方面。
软件复用的软件支持
支持软件复用是人们对面向对象方法寄托的主要希望之一,也是这种方法受到广泛重视的主要原因之一。面向对象方法之所以特别有利于软件复用,是由于它的主要概念及原则与软件复用的要求十分吻合。
面向对象方法
面向对象方法从面向对象的编程发展到面向对象的分析与设计,使这种方法支持软件复用的固有特征能够从软件生命周期的前期阶段开始发挥作用,从而使OO方法对软件复用的支持达到了较高的级别。
与其它软件工程方法相比,面向对象方法的一个重要优点是,它可以在整个软件生命周期达到概念、原则、术语及表示法的高度一致。这种一致性使得各个系统成分尽管在不同的开发与演化阶段有不同的形态,但可具有贯穿整个软件生命周期的良好映射。
这一优点使OO方法不但能在各个级别支持软件复用,而且能对各个级别的复用形成统一的、高效的支持,达到良好的全局效果。做到这一点的必要条件是,从面向对象软件开发的前期阶段—OOA就把支持软件复用作为一个重点问题来考虑。运用OOA方法所定义的对象类具有适合作为可复用构件的许多特征,OOA结果对问题域的良好映射,使同类系统的开发者容易从问题出发,在已有的OOA结果中发现不同粒度的可复用构件。
三方面讲述软件复用
类
代码复用
包括目标代码和源代码的复用。源代码的复用级别略高于目标代码的复用,程序员在编程时把一些想复用的代码段复制到自己的程序中,但这样往往会产生一些新旧代码不匹配的错误。想大规模的实现源程序的复用只有依靠含有大量可复用构件的构件库。
设计的复用
设计结果比源程序的抽象级别更高,因此它的复用受实现环境的影响较少,从而使可复用构件被复用的机会更多,并且所需的修改更少。这种复用有三种途径:
1、 第一种途径是从现有系统的设计结果中提取一些可复用的设计构件,并把这些构件应用于新系统的设计;
2、 第二种途径是把一个现有系统的全部设计文档在新的软硬件平台上重新实现,也就是把一个设计运用于多个具体的实现;
3、第三种途径是独立于任何具体的应用,有计划地开发一些可复用的设计构件。
分析的复用
分析的复用是比设计结果更高级别的复用,可复用的分析构件是针对问题域的某些事物或某些问题的抽象程度更高的解法,受设计技术及实现条件的影响很少,所以可复用的机会更大。复用的途径也有三种,
1、从现有系统的分析结果中提取可复用构件用于新系统的分析;
2、 用一份完整的分析文档作输入产生针对不同软硬件平台和其它实现条件的多项设计;
3、独立于具体应用,专门开发一些可复用的分析构件。
测试信息的复用
测试信息的复用主要包括测试用例的复用和测试过程信息的复用。前者是把一个软件的测试用例在新的软件测试中使用,或者在软件作出修改时在新的一轮测试中使用。后者是在测试过程中通过软件工具自动地记录测试的过程信息,包括测试员的每一个操作、输入参数、测试用例及运行环境等一切信息。
这种复用的级别,不便和分析、设计、编程的复用级别作准确的比较,因为被复用的不是同一事物的不同抽象层次,而是另一种信息,但从这些信息的形态看,大体处于与程序代码相当的级别。
Liskov替换原则 ——LSP
里氏替换原则的主要作用就是规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖。
含义如下:
子类必须完全实现父类的方法
子类可以有自己的个性 覆盖或实现父类的方法时输入参数可以被放大 覆盖或实现父类的方法时输出结果可以被缩小
LSP是子类型关系的一个特殊定义,称为(强)行为子类型化。在编程语言中,LSP依赖于以下限制:
前置条件不能强化 后置条件不能弱化 不变量要保持或增强 子类型方法参数:逆变 子类型方法的返回值:协变 异常类型:协变
API
建议:始终以开发API的标准面对任何开发任务;面向“复用”编程而不是面向“应用”编程。
难度:要有足够良好的设计,一旦发布就无法再自由改变。
编写一个API需要考虑以下方面:
API应该做一件事,且做得很好
API应该尽可能小,但不能太小
Implementation不应该影响API
记录文档很重要
考虑性能后果
API必须与平台和平共存
类的设计:尽量减少可变性,遵循LSP原则
方法的设计:不要让客户做任何模块可以做的事情,及时报错
框架
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。
前者是从应用方面而后者是从目的方面给出的定义。为了增加代码的复用性,可以使用委派和继承机制。同时,在使用这两种机制增加代码复用的过程中,我们也相应地在不同的类之间增加了关系(委派或继承关系)。而对于一个项目而言,各个不同类之间的依赖关系就可以看做为一个框架。一个大规模的项目可能由许多不同的框架组合而成。
框架与设计模式:
框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的。构件通常是代码重用,而设计模式是设计重用,框架则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。
设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更抽象;框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用代码表示;设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用。可以说,框架是软件,而设计模式是软件的知识。
框架分为白盒框架和黑盒框架。
白盒框架
通过子类化和重写方法进行扩展(使用继承);
通用设计模式:模板方法;
子类具有主要方法但对框架进行控制。 允许扩展每一个非私有方法
需要理解父类的实现 一次只进行一次扩展 通常被认为是开发者框架
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";
}
}
黑盒框架
通过实现插件接口进行扩展(使用组合/委派);
常用设计模式:Strategy, Observer ;
插件加载机制加载插件并对框架进行控制。
> 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();
> } }
一点心得
我们可能都学过乘法口诀表,我们学口诀的目标不是以后碰到的时候知道符合哪一个口诀,而是能把我们碰到的不论多复杂的问题转化为我们熟悉的口诀进而解决。23种设计模式存在的目的也是如此。四人帮在出版《设计模式》时曾说过,设计模式体现的是一种思想。理解和掌握了23种设计模式,并不是说记住了23种设计场景和解决策略。而是一种思想,这种思想是知道我们设计和编程的本质的东西。而这种思想,是以抽象和解耦合为最高宗旨的。在之后的学习中,我会在继续学习,不断进步。