软件构造(7)- 可复用性

面向复用的软件构造技术
  1. 设计可复用的类

    1. LSP原则
      客户端可用统一的方式处理 不同类型的对象
      在可以使用父类对象的场景,都可以用子类对象代替而不会有任何问题
      静态检查规则:
      (1) 子类型可以增加方法,但不可删
      (2) 子类型需要实现抽象类型中的所有未实现方法
      (3) 子类型中重写的方法必须有相同或子类型的返回值
      (4) 子类型中重写的方法必须使用同样类型的参数
      (5) 子类型中重写的方法不能抛出额外的异常
      == 更强的不变量,更弱的前置条件,更强的后置条件 ==

    LSP原则:强行为子类型化
    软件构造(7)- 可复用性_第1张图片
    协变:
    父类型->子类型:越来越具体specific;返回值/异常类型:不变或变得更具体
    子类型返回值是父类型返回值的子类型;
    子类型中异常要与父类型相同/父类中的子类型/不抛出
    数组是协变的:类型为T的数组可以包含类型为T的元素或T子类的元素
    泛型不是协变的:
    但可采用类型通配符(List)避免协变现象
    表示下界的通配符: 与所有A的父类型匹配
    表示上界的通配符: 与所有A的子类匹配

List myInt = new ArrayList();
List myNums = myInt; //error!  泛型不是协变的!

Box 不是 Box 的子类型

反协变,逆变
父类型->子类型:越来越具体specific;参数类型:不变或越来越抽象
Java中当作Overload

  1. Delegation and Composition
    ADT 比较大小 或放入Collections或Arrays进行排序
    method1:实现Comparator接口并override compare()函数
//client
public void sort(List edges) {
	Comparator comparator = new EdgeComparator();
	//委派
	Collections.sort(edges, comparator);
}
//class
public class EdgeComparator implements Comparator{
	//重写的compare方法
	@Override
	public int compare(Edge o1, Edge o2) {
		if(o1.getWeight() > o2.getWeight())
			return 1;
		else if (.. == ..) return 0;
		else return -1;
	}
}

method2:ADT实现Comparable接口,然后override compareTo() 方法
与使用Comparator的区别:不需要构建新的Comparator类,比较代码放在ADT内部
不再有委派出现

public class Edge implements Comparable {
	Vertex s, t;
	double weight;
	...
	public int compareTo(Edge o) {
		if(this.getWeight() > o.getWeight())
			return 1;
		else if (.. == ..) return 0;
		else return -1;
	}
}

Delegation委派/委托:一个对象请求另一个对象的功能
委派模式:通过运行时动态绑定,实现对其他类中代码的动态复用(复用的一种常见形式)
可实现功能改造:
如下为可查看日志的log
软件构造(7)- 可复用性_第2张图片
使用委派的情况:
子类只需要复用父类中的一小部分方法,可不需继承,通过委托机制调用部分方法,避免大量无用的方法。
“委托”发生在object层面,而“继承”发生在class层面

Composite Reuse Principle (CRP原则)
软件构造(7)- 可复用性_第3张图片
更普适的使用继承:
使用接口定义系统必须对外展示的不同侧面的行为
接口之间通过extends实现行为的扩展(接口组合)
类implements 组合接口,从而规避了复杂的继承关系

(1)Dependency:临时性的delegation:没有用来保存delegation的域
一个类利用另一个类里的函数,但不把这个类的对象作为属性。该对象可能是参数或者是方法里的局部变量。这种关系被称为"use-a"

class Duck {
	//no field to keep Flyable object
	void fly(Flyable f) {
		f.fly();
	}
}
//client
Flyable f = new FlyWithWings();
Quackable q = new Quack();
Duck d = new Duck();
d.fly(f);
d.quack(q);

(2)Association: 永久性的delegation(包括Composition,Aggregation)
"has_a"关系

  • Composition: 更强的association,但难以变化
    "is_part_of"关系
class Duck {
	Flyable f = new FlyWithWings();
	void fly() {
		f.fly();
	}
}
//client
Duck d = new Duck();
d.fly();
  • Aggregation: 更弱的association,可动态变化
class Duck {
	Flyable f;
	void Duck(Flyable f) { 
		this.f = f; 
	}
	void setFlyBehavior(f) {
		this.f = f;
	}
	void fly() { f.fly();}
}
//client
Flyable f = new FlyWithWings();
Duck d = new Duck(f);
d.fly();
d.setFlyBehavior(new CannotFly());//动态变化
d.fly();

白/黑盒框架的原理与实现:

  1. 白盒框架 – 继承 知道其内部实现
    通过子类型与重写进行扩展
    常用的设计模式:Template Method
  2. 黑盒框架 – 委派/组合 只知道接口方法
    通过重写plugin interface进行扩展
    常用的设计模式:Strategy, Observer

你可能感兴趣的:(软件构造)