-
可复用的不仅仅只有代码,最主要的复用是在代码层面, 但软件构造过程中的任何实体都可能被复用,如需求、设计/规约spec、数据、测试用例、文档。
-
代码复用的类型:
(1) 白盒复用:源代码可见,可修改和扩展。通过继承进行复用。
(1) 黑盒复用:源代码不可见,不能修改。通过实现接口/委托复用。 -
设计可复用的类:继承与重写、重载、参数多态与泛型编程、行为子类型与Liskov替换原则、组合与委托。
-
Liskov替换原则:
子类型可以增加方法,但不可删;
子类型需要实现抽象类型中的所有未实现方法;
子类型中重写的方法必须有相同或子类型的返回值或者符合co-variance的参数;
子类型中重写的方法必须使用同样类型的参数或者符合contra-variance的参数;
子类型中重写的方法不能抛出额外的异常;
更强的不变量;
更弱的前置条件;更强的后置条件(规约更强)。
(斜体加粗部分不可被Java静态检测检查出来)
更强的不变量例子(子类型应当完整保持父类型中属性的RI,不能改变,可以增加新的属性的RI):
-
协变与反协变
协变:对于同一个方法,子类的返回值比父类更确切。
反协变:对于同一个方法,子类的参数比父类更抽象。(编译器不支持,java将其当作重载看待)
父类型->子类型:越来越具体specific
参数类型:要相反的变化,要不变或越来越抽象。 -
Java中数组是支持协变的:
图中最后一条语句错误是因为这是赋值操作,调用了valueOf(),不会进行转换。 -
泛型中的LSP
例子:
当带通配符“?”时,list间可以存在父子关系。"?":任意类;"<? super A>":A和A的父类;"<? extends A>":A和A的子类。
例:List is a subtype of List<? super String> -
ADT比较大小:
(1) 实现Comparator接口并override compare()函数
(2) 让你的ADT实现Comparable接口,然后override
compareTo() 方法。 -
委托的方式:
(1) 临时性委托:通过方法的参数委托
(2) 永久性委托:通过属性委托。又分为聚合(Aggregation: 更弱的association,可动态变化)和组合( Composition: 更强的association,但难以变化)。
聚合:
组合:
-
白盒框架:基于继承,子类对象执行;
黑盒框架:基于接口,框架执行。 -
面向复用的设计模式。
(1) 设计(Structural)模式
(a) 适配器(Adapter)模式:解决接口不匹配的问题
(b) 装饰(Decorator)模式:为对象增加不同侧面的特性,这些属性可以任意组合。
例子:
(c) 门面(Facade)模式:提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用。
例子:
使用门面模式后:
使用:
(2) 行为(Behavioral)模式
(a)策略(Strategy)模式:有多种不同的算法来实现同一个任务,但需要client根据需要动态切换算法,而不是写死在代码里
(b) 模板(Template)模式:共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现,如白盒框架(继承)。
(c)迭代器(Iterator)模式:让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个迭代器进行显式或隐式的迭代遍历。
可复用性复习概要
最新推荐文章于 2024-10-10 21:34:07 发布