从类,API,框架三个层面学习设计可复用软件

(1)代码的复用
包括目标代码和源代码的复用。其中目标代码的复用级别最低,历史也最久,当前大部分编程语言的运行支持系统都提供了连接(Link)、绑定(Binding)等功能来支持这种复用。源代码的复用级别略高于目标代码的复用,程序员在编程时把一些想复用的代码段复制到自己的程序中,但这样往往会产生一些新旧代码不匹配的错误。想大规模的实现源程序的复用只有依靠含有大量可复用构件的构件库。如”对象链接及嵌入”(OLE)技术,既支持在源程序级定义构件并用以构造新的系统,又使这些构件在目标代码的级别上仍然是一些独立的可复用构件,能够在运行时被灵活的得新组合为各种不同的应用。

(2)设计的复用
设计结果比源程序的抽象级别更高,因此它的复用受实现环境的影响较少,从而使可复用构件被复用的机会更多,并且所需的修改更少。这种复用有三种途径,第一种途径是从现有系统的设计结果中提取一些可复用的设计构件,并把这些构件应用于新系统的设计;第二种途径是把一个现有系统的全部设计文档在新的软硬件平台上重新实现,也就是把一个设计运用于多个具体的实现;第三种途径是独立于任何具体的应用,有计划地开发一些可复用的设计构件。

(3)分析的复用
这是比设计结果更高级别的复用,可复用的分析构件是针对问题域的某些事物或某些问题的抽象程度更高的解法,受设计技术及实现条件的影响很少,所以可复用的机会更大。复用的途径也有三种,即从现有系统的分析结果中提取可复用构件用于新系统的分析;用一份完整的分析文档作输入产生针对不同软硬件平台和其它实现条件的多项设计;独立于具体应用,专门开发一些可复用的分析构件。

(4)测试信息的复用
主要包括测试用例的复用和测试过程信息的复用。前者是把一个软件的测试用例在新的软件测试中使用,或者在软件作出修改时在新的一轮测试中使用。后者是在测试过程中通过软件工具自动地记录测试的过程信息,包括测试员的每一个操作、输入参数、测试用例及运行环境等一切信息。这种复用的级别,不便和分析、设计、编程的复用级别作准确的比较,因为被复用的不是同一事物的不同抽象层次,而是另一种信息,但从这些信息的形态看,大体处于与程序代码相当的级别。

由于软件生产过程主要是正向过程,即大部分软件的生产过程是使软件产品从抽象级别较高的形态向抽象级别较低的形态演化,所以较高级别的复用容易带动较低级别的复用,因而复用的级别越高,可得到的回报也越大,因此分析结果和设计结果在目前很受重视。用户可购买生产商的分析件和设计件,自己设计或编程,掌握系统的剪裁、扩充、维护、演化等活动。

设计可复用的类

在OOP中设计可复用的类
封装和信息隐藏
继承和重写
多态性,子类型和重载
泛型编程
行为子类型和Liskov替代原则(LSP)
组合与委托

 

 

API

API:应用程序编程接口,库或框架的接口

客户端:使用API的代码 插件:定制框架的客户端代码
扩展点:框架内预留的“空白”,开发者开发出符合接口要求的代码(即插件),框架可调用,从而相当于开发者扩展了框架的功能
协议:API和客户端之间预期的交互顺序
回调:框架调用来访问定制功能的插件方法
生命周期方法:根据协议和插件状态按顺序调用的回调方法
建议:始终以开发API的标准面对任何开发任务;
面向“复用”编程而不是面向“应用”编程。
难度:要有足够良好的设计,一旦发布就无法再自由改变。

编写一个API需要考虑以下方面:

API应该做一件事,且做得很好

API应该尽可能小,但不能太小

Implementation不应该影响API

记录文档很重要

考虑性能后果

API必须与平台和平共存

类的设计:尽量减少可变性,遵循LSP原则

方法的设计:不要让客户做任何模块可以做的事情,及时报错

LSP原则

定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 T1 的子类型。

定义2:所有引用基类的地方必须能透明地使用其子类的对象。

问题由来:
有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后 的功 能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。

解决方案:
当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法

LSP依赖于以下限制:
前置条件不能强化
后置条件不能弱化
不变量要保持
子类型方法参数:逆变
子类型方法的返回值:协变
异常类型:协变

 

Covariance (协变):
父类型->子类型:越来越具体specific 。
返回值类型:不变或变得更具体 。
异常的类型:也是如此。

å¨è¿éæå¥å¾çæè¿°

继承包含这样一层含义:父类中凡是已经实现好的方法(相对于抽象方法而言),实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些契约,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义

 

框架

框架(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"; 
    }
}
通过子类化和重写方法进行扩展(使用继承);
通用设计模式:模板方法;
子类具有主要方法但对框架进行控制。 允许扩展每一个非私有方法
需要理解父类的实现 一次只进行一次扩展 通常被认为是开发者框架
黑盒框架:
黑盒框架时基于委派的组合方式,是不同对象之间的组合。之所以是黑盒,是因为不用去管对象中的方法是如何实现的,只需关心对象上拥有的方法。这种方式较白盒框架更为灵活,因为可以在运行时动态地传入不同对象,实现不同对象间的动态组合;而继承机制在静态编译时就已经确定好。
黑盒框架与白盒框架之间可以相互转换,具体例子可以看一下,软件构造课程中有关黑盒框架的例子,更改上面的白盒框架为黑盒框架

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(); 
    }
}
 

心得

软件复用的好处:
一、提高工作效率
这条自不必说,比如在项目A中你写一个Ajax模块,A完工后启动了项目B,在B中就可以直接复用项目A的模块了。一个可复用的软件可以为将来节省费用,被服用的频率越高,组件的初始开发成本就越低。
二、提高软件质量
可复用的软件总比不能复用的有更多的质量保障。因为可复用的软件在不断的复用过程中把一些bug,缺陷都很快的排除了。因此可复用的软件一定是利于系统的可维护性的。按抽象程度的高低,可以划分为如下的复用级别:代码的剪贴复制
利用编辑器(IDE)可以很方便的做到减少抄写代码的人力成本。这可能是入门级程序员习惯的,自发的复用软件的形式。把一个写好的工具函数自发的拷贝到另一个功能或项目中。这种方式有着明显的缺点就是他造成很多重复冗余的代码。尤其在Web前端开发中,JavaScript资源的量大小影响着客户端下载速度。好一点的复用方式可以采用继承。算法的复用
各种算法比如排序都已经得到了大量的研究。几乎不需要你重新去写自己的算法,各种语言通常也实现了这些常用算法。因此你只需要直接复用。

设计的复用
设计结果比源程序的抽象级别更高,因此它的复用受实现环境的影响较少,从而使可复用构件被复用的机会更多,并且所需的修改更少。
这种复用有三种途径
第一种途径是从现有系统的设计结果中提取一些可复用的设计构件,并把这些构件应用于新系统的设计;
第二种途径是把一个现有系统的全部设计文档在新的软硬件平台上重新实现,也就是把一个设计运用于多个具体的实现;
第三种途径是独立于任何具体的应用,有计划地开发一些可复用的设计构件。

分析的复用
这是比设计结果更高级别的复用,可复用的分析构件是针对问题域的某些事物或某些问题的抽象程度更高的解法,受设计技术及实现条件的影响很少,所以可复用的机会更大。复用的途径也有三种,即从现有系统的分析结果中提取可复用构件用于新系统的分析;用一份完整的分析文档作输入产生针对不同软硬件平台和其它实现条件的多项设计;独立于具体应用,专门开发一些可复用的分析构件。

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值