设计可复用软件实体的具体技术

1.可复用软件

软件复用(SoftWare Reuse)是将已有软件的各种有关知识用于建立新的软件,以缩减软件开发和维护的花费。软件复用是提高软件生产力和质量的一种重要技术。早期的软件复用主要是代码级复用,被复用的知识专指程序,后来扩大到包括领域知识、开发经验、设计决定、体系结构、需求、设计、代码和文档等一切有关方面。

软件复用是一种计算机软件工程方法和理论。60年代的“软件危机”使程序设计人员明白难于维护的软件成本是极其高昂的,当软件的规模不断扩大时,这种软件的综合成本可以说是没有人能负担的,并且即使投入了高昂的资金也难以得到可靠的产品,而软件重用的思想是解决这一问题的根本方法 。

软件复用的主要思想是,将软件看成是由不同功能部分的“组件”所组成的有机体,每一个组件在设计编写时可以被设计成完成同类工作的通用工具,这样,如果完成各种工作的组件被建立起来以后,编写一特定软件的工作就变成了将各种不同组件组织连接起来的简单问题,这对于软件产品的最终质量和维护工作都有本质性的改变。

软件复用就是将已有的软件成分用于构造新的软件系统。可以被复用的软件成分一般称作可复用构件,无论对可复用构件原封不动地使用还是作适当的修改后再使用,只要是用来构造新软件,则都可称作复用。软件复用不仅仅是对程序的复用,它还包括对软件生产过程中任何活动所产生的制成品的复用,如项目计划、可行性报告、需求定义、分析模型、设计模型、详细说明、源程序、测试用例等等。如果是在一个系统中多次使用一个相同的软件成分,则不称作复用,而称作共享;对一个软件进行修改,使它运行于新的软硬件平台也不称作复用,而称作软件移值。

2.类

2.1设计可复用类–LSP

在OOP之中设计可复用的类
1.封装和信息隐藏
2.继承和重写
3.多态、子类和重载
4.泛型编程
5.LSP原则
6.委派和组合

2.1.1 行为子结构

解释:客户端可用统一的方式处理不同类型的对象
例子:

Animal a = new Animal();
Animal c1 = new Cat();
Cat c2 = new Cat();

在可以使用a的场景,都可以用c1和c2代替而不会有任何问题。

在java的静态类型检查之中,编译器强调了几条规则:

  1. 子类型可以增加方法,但不可删
  2. 子类型需要实现抽象类型中的所有未实现方法。
  3. 子类型中重写的方法必须有相同或子类型的返回值。
  4. 子类型中重写的方法必须使用同样类型的参数。
  5. 子类型中重写的方法不能抛出额外的异常

行为子结构也适用于指定的方法:
1 . 更强的不变量
2. 更弱的前置条件
3. 夏强的后置条件

2.1.2 逆变与协变

逆变与协变综述:如果A、B表示类型,f()表示类型转换,≤表示继承关系(比如,A<B表示A是由B派生

  1. f()是逆变(contravariant)的,当A<B时有f(B)≤f(A)成立;
  2. f(·)是协变(covariant)的,当A≤B时有f(A)≤f(B)成立;
  3. f()是不变(invariant)的,当A≤B时上述两个式子均不成立,即f(A)与f(B)相互之间没有继承关系。

协变(Co-variance) :

  1. 父类型->子类型:越来越具体(specific)。
  2. 在LSP中,返回值和异常的类型:不变或变得更具体。

逆变(Contra-variance):

  1. 父类型->子类型:越来越抽象。
  2. 参数类型:要相反的变化,不变或越来越抽象。
  3. 但这在Java中是不允许的,因为它会使重载规则复杂化。

2.1.3 Liskov替换原则(LSP)

里氏替换原则的主要作用就是规范继承时子类的一些书写规则。其主要目的就是保持父类方法不被覆盖

  1. 子类必须完全实现父类的方法。子类可以有自己的个性
  2. 覆盖或实现父类的方法时输入参数可以被放大。覆盖或实现父类的方法时输出结果可以被缩小

LSP是子类型关系的一个特殊定义,称为(强)行为子类型化。在编程语言中,LSP依赖于以下限制:

  1. 前置条件不能强化
  2. 后置条件不能弱化。不变量要保持或增强
  3. 异常类型:协变
  4. 子类型方法参数:逆变
  5. 子类型方法的返回值:协变

2.2 各种应用中的LSP

【数组是协变的】

  • 数组是协变的:一个数组T[],可能包含了T类型的实例或者T的任何子类型的实例
  • 即子类型的数组可以赋予父类型的数组进行使用,但数组的类型实际为子类型。
  • 下面报错的原因是myNumber指向的还是一个Integer[]而不是Number[]
Number[]numbers = new Number[2];
numbers[0] = new Integer(10);
numbers[1] = new Double(3.14);
lnteger[]mylnts = {1,2,3,4};Number[]myNumber = mylnts;
myNumber[0] = 3.14;l/run-time error!

2.3 泛型中的LSP

Java中泛型是不变的,但可以通过通配符"?"实现协变和逆变:

  • <? extends>实现了泛型的协变:
  • List<? extends Number> list = new ArrayList();
  • <? super>实现了泛型的逆变:
  • List<? super Number> list = new ArrayList();

由于泛型的协变只能规定类的上界,逆变只能规定下界,使用时需要遵循PECS (producer–extends,consumer-super:

  • 要从泛型类取数据时,用extends;
  • 要往泛型类写数据时,用super;
  • 既要取又要写,就不用通配符(即extends与super都不用)。

泛型是类型不变的(泛型不是协变的)。举例来说

  • ArrayList是List的子类型
  • List<String-不是List的子类型
  1. 在代码的编译完成之后,泛型的类型信息就会被编译器擦除。因此,这些类型信息并不能在运行阶段时被获得。这一过程称之为类型擦除(type erasure) 。

  2. 类型擦除的详细定义:如果类型参数没有限制,则用它们的边界或Qbject来替换泛型类型中的所有类型参数。因此,产生的字节码只包含普通的类、接口和方法。

  3. 类型擦除的结果:被擦除T变成了Object

  4. Integer是number的子类型,但Box也不是Box的子类型

  5. 这对于类型系统来说是不安全的,编译器会立即拒绝它。

3.API和库

  • API是程序员最重要的资产和“荣耀”",吸引外部用户,提高声誉
  • 建议: 始终以开发API的标准面对任何开发任务;面向“复用"编程而不是面向“应用"编程。
  • 难度:要有足够良好的设计,一旦发布就无法再自由改变。

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

  • API应该做一件事,且做得很好
  • API应该尽可能小,但不能太小
  • lmplementation不应该影响API
  • 记录文档很重要
  • 考虑性能后果
  • API必须与平台和平共存
  • 类的设计:尽量减少可变性,遵循LSP原则
  • 方法的设计:不要让客户做任何模块可以做的事情,及时报错

4.框架

之所以lirary和framework被称为系统层面的复用,是因为它们不仅定义了1个可复用的接口/类,而是将某个完整系统中的所有可复用的接口/类都实现出来,并且定义了这些类之间的交互关系、调用关系,从而形成了系统整体的"架构”。

4.1相应术语

  • API (Application Programming Interface) :库或框架的接口o Client(客户端):使用API的代码
  • Plugin(插件)∶客户端定制框架的代码
  • Extension Point:框架内预留的"空白"”,开发者开发出符合接口要求的代码(即plugin),框架可调用,从而相当于开发者扩展了框架的功能
  • Protocol(协议): API与客户端之间预期的交互序列。 -
  • Callback(反馈):框架将调用的插件方法来访问定制的功能
  • Lifecycle method:根据协议和插件的状态,按顺序调用的回调方法。

4.2 框架

  • 框架((Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义。
  • 为了增加代码的复用性,可以使用委派和继承机制。同时,在使用这两种机制增加代码复用的过程中,我们也相应地在不同的类之间增加了关系(委派或继承关系)。而对于一个项目而言,各个不同类之间的依赖关系就可以看做为一个框架。一个大规模的项目可能由许多不同的框架组合而成。
    ·

框架与设计模式:

  • 框架、设计模式这两个概念总容易被混淆,其实它们之间还是有区别的。构件通常是代码重用,而设计模式是设计重用,框架则介于两者之间,部分代码重用,部分设计重用,有时分析也可重用。在软件生产中有三种级别的重用:内部重用,即在同一应用中能公共使用的抽象块;代码重用,即将通用模块组合成库或工具集,以便在多个应用和领域都能使用;应用框架的重用,即为专用领域提供通用的或现成的基础结构,以获得最高级别的重用性。

  • 框架与设计模式虽然相似,但却有着根本的不同。设计模式是对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比框架更抽象;框架可以用代码表示,也能直接执行或复用,而对模式而言只有实例才能用代码表示;设计模式是比框架更小的元素,一个框架中往往含有一个或多个设计模式,框架总是针对某一特定应用领域,但同一模式却可适用于各种应用。可以说,框架是软件,而设计模式是软件的知识。

框架分为白盒框架和黑盒框架:
白盒框架:

  • 白盒框架是基于面向对象的继承机制。之所以说是白盒框架,是因为在这种框架中,父类的方法对子类而言是可见的。子类可以通过继承或重写父类的方法来实现更具体的方法。
  • 虽然层次结构比较清晰,但是这种方式也有其局限性,父类中的方法子类一定拥有,要么继承,要么重写,不可能存在子类中不存在的方法而在父类中存在。.
  • 软件构造课程中有关白盒框架的例子:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值