软件构造第四章复习

4.1可复用性的度量,形态和外部表现

一.软件复用(面向复用编程+基于复用编程)

面向复用编程:开发可复用软件
基于复用编程:利用已有可复用软件搭建应用系统
复用的好处是可以降低成本和时间,但是需要标准化

二.复用方式和复用层次

1.复用方式

(1).白盒复用:源代码可见,可修改可扩展
(2).黑盒复用:源代码不可见,不可修改

2.复用层次

(1).代码复用:复制一部分或全部源代码,根据实际情况修改代码
(2).类或接口的复用:将一些架包以压缩包的形式打包放入classpath中使用
(3).API复用:类库复用
(4).框架复用:一组具体类,抽象类及其之间的联系关系复用,内部实现需要复用者完成

三.可复用性的外部表现

类型可变(泛型):适应不同的类型,且满足LSP原则
实现可变:ADT有不同的Rep和AF,但是spoc(规约)是不变的
表示独立:内部的改变不影响客户端的实现
共性抽取:将相同的行为抽取出来形成可复用的方法或者类

4.2面向复用的软件构造技术

一.设计可复用类

1.子类型多态:客户端可以用统一的方式处理不同类型的对象

例如Cat是Animal的子类

Animal a = new Animal();
Animal b = new Cat();
Cat c = new Cat();
//在任何可以使用a的情况,都可以用b,c代替

2.LSP(李氏替换原则)(重点)

若类型T的对象x,q(x)成立;则对于类型T的子类型S的对象y,q(y)也成立
主要可以分为以下五点:
(1).子类型可以增加方法,但不可以删除
(2).子类型需要实现抽象类型(接口,抽象类)中所有未实现的方法
(3).子类型中重写的方法必须有相同或子类型的返回值符合co-varient(协变)的参数
(4).子类型中重写的方法必须使用相同类型的参数或符合contra-varient(逆变)的参数
(5).子类型中重写的方法不能抛出额外的异常

3.协变和逆变

(1).协变:同方向变化

例:

class T{
	Object a(){...}
}
class S extends T(){
	@override
	String a(){...}
}

其中S是T的子类,且重写方法中String也是Object的子类

(2).逆变:反方向变化

例:

class T{
	void c(String s){...}
}
class S extends T(){
	@override
	void c(Object s){...}
}

其中S是T的子类,但重写方法中Object是String的父类
注:Java将逆变视为overload(重载),若加入@override则会报错

4.泛型,通配符

(1).泛型

泛型是类型不变的(不协变)
如:ArrayList< String >是List< String >的子类
但是List< String >不是List< Object >的子类
原因:类型擦除,即类型参数在编译后被丢弃,在运行时不可用

(2).通配符(用于实现两个泛型类的协变)

1.<?>:无限定通配符(任何类型都是适配的)
2.<? super A>:下限通配符(A以及A的父类都是适配的)
3.<? extends A>:上限通配符(A以及A的子类都是适配的)
注:通配符意味着(以List为例)可以匹配多种类型中的一种,并不代表同一个List中可存放多种类型的数据。

二.委托(Delegation)和重组(Composition)

1.委托(一个对象请求另一个对象的功能)

例:

class A{
	void foo(){
		this.bar();
	}
	void bar(){
		system.out.println("a.bar");
	}
}
class B{
	private A a;//delegation link(委托连接)
	public B(A a){
		this.a = a;
	}
	void foo(){
		a.foo();//通过调用A的foo来实现
	}
	void bar(){
		system.out.println("b.bar");
	}
}
//执行以下代码
A a = new A();
B b = new B(a);
b.foo();

执行结果为:a.bar

委托主要可以分为以下四种
(1).临时性的委托
(2).永久性的委托
(3).更强的永久性委托,但难以变化
(4).更弱的永久性委托,但可以动态变化

2.CRP(基于组合的重组原则)

(1).通过接口定义系统必须对外展示不同的侧面行为
(2).接口之间通过extends实现行为拓展
(3).类implements组合接口

4.3面向复用的设计模式

一.结构型模式

1.适配器模式

将某个类或者接口转换为client期望的其他形式
可以解决类之间接口不兼容的问题

2.装饰器模式(重点)

以一个冰激凌的制作为例

public interface Icecream{//顶层接口
	void AddTopping();
}
public class PlainIcecream implements Icecream{//基础实现,无添加的冰激凌
	@override
	public void AddTopping(){
		system.out.println("Plain Icecream ready for some toppings");
	}
}
public abstract class ToppingDecorator implement Icecream{//装饰器基类
	protected final Icecream input;
	public ToppingDecorator(Icecream i){
		this.input = i;
	}
	public abstract void AddTopping();//留给具体装饰类实现 
}
public class CandyTopping extends ToppingDecorator{
	public CandyTopping(Icecream i){
		super(i);
	}
	public void AddTopping(){
		input.AddTopping();
		system.out.println("Candy Topping added!");
	}
}
public class NutTopping extends ToppingDecorator{
	public NutTopping(Icecream i){
		super(i);
	}
	public void AddTopping(){
		input.AddTopping();
		system.out.println("Nut Topping added!");
	}
}

3.外观模式

客户端通过一个简化的接口来访问复杂系统中的功能

二.行为型模式

1.策略模式:让用户端从待选方法中选择某一项完成
2.模板模式:做事情的步骤一样,但具体方法不同
3.迭代器模式:用户希望对于任何数据,都有相同的迭代方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值