【软件构造】软件构造复习总结3-第四、五章部分
第四五章主要复习了各种设计模式。
第四章
一、可复用性的度量、形态学和外部观察
1.源代码复用;模块复用(类或接口);库复用(API);系统复用(框架)。
2.白盒框架:通过继承和动态绑定实现可扩展性,通过继承框架基类并重写预定义的钩子方法来扩展现有功能
3.黑盒框架:通过定义符合特定接口的组件来重用现有功能,这些组件通过委托与框架集成
二、面向复用的软件构造技术
1.LSP:在任何父类型可一应用的场景,子类型都可以应用。
重写的方法可以有相同的前置和后置条件。也可以有更弱的前置条件或更强的后置条件。
2.协变:父类型->子类型:越来越具体specific 返回值类型:不变或变得更具体异常的类型:也是如此。如:
逆变:父类型->子类型:越来越具体specific 参数类型:要相反的变化,要不变或越来越抽象。如:
3.泛型中的LSP:ArrayList是List的子类,ArrayList不是List的子类。
例.
static long sum(List<Number> list) {
long sum = 0;
for(Number number : list) {
sum+= number.longValue();
}
return sum;
}
public static void main(String[] args){
List<Integer> list = List.of(1,2,3);
System.out.println(sum(list));
}
Sum会报错:
不可以认为List是List的子类进行传入。
4.<?>通配符:使用例子:
客户端:
public static void main(String[] args){
List<Integer> li = Arrays.asList(1, 2, 3);
List<String> ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);
}
printList的目标是打印任何类型的列表,但是它无法实现这个目标-它只打印对象实例的列表;它不能打印list、list和list等等,因为它们不是list的子类型。
要编写通用的printList方法,使用List<?>。
控制台:
5.<? super A>与 <? extends A> :如:
前者只匹配整数类型的列表,而后者匹配整数超类型(如Integer、Number和Object)的任何类型的列表。
5.Comparator<…>接口,如果ADT需要比大小可以实现该接口并override compareTo(Object o)或compare(Object o1, Object o2)函数。
可以使用Collections.sort(this.o);进行排序
6.委派(delegation):一个对象请求另一个对象的功能。
7.CRP(复合重用原则):类应该通过组合所需功能,而不是通过继承来实现多态和复用。重点理解:
8.各种委派:
a.Dependency: 临时性的delegation,如:
b.Association: 永久性的delegation,如:
c. Composition: 更强的association,但难以变化,如:
d.Aggregation: 更弱的association,可动态变化,如:
三、面向复用的设计模式
1.Structural patterns 结构型模式:处理类或对象的组合。
a.Adapter适配器模式:将某个类/接口转换为client期望的其他形式.
通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。
b. Decorator装饰器模式:为对象增加不同侧面的特性.
对每一个特性构造子类,通过委派机制增加到对象上
例子类比:
Decorator通过delegate到stack完成基本操作,在decorator基础上通过继承增添新的功能。
c. Facade外观模式:客户端需要通过一个简化的接口来访问复杂系统内的功能。
提供一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用。
2.Behavioral patterns 行为类模式:描述类或对象交互和分配责任的方式。
a. Strategy策略模式:为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例。
b.Template Method模板模式:共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。
与白盒框架类似。
c. Iterator迭代器:客户端希望遍历被放入容器/集合类的一组ADT对象,无需关心容器的具体类型。
主要实现方式:两个接口,Iterable和Iterator。
自己的类实现Iterable接口,并创造一个新类实现迭代器。
遍历:
以实验为例,实验中让实现board的迭代。
首先创造一个BoardIterator实现Iterator接口
public class BoardIterator implements Iterator<PlanningEntry<Resource>>{
private PlanningEntryCollection pec;
private int count = 0;
// Abstraction function:
// AF(BoardIterator)={pec , count| pec映射是一系列计划项,count映射是第几个计划项}
// Representation invariant:
// nothing
// Safety from rep exposure:
// 所有变量都是private的
//
/**
* BoardIterator的构造器
* @param pec 一系列计划项
*
*/
public BoardIterator(PlanningEntryCollection pec) {
this.pec = pec;
Collections.sort(this.pec.getPes());
}
/**
*
* @return boolean
*
*/
@Override
public boolean hasNext() {
return count < pec.getPes().size();
}
/**
*
* @return PlanningEntry<Resource>
*
*/
@Override
public PlanningEntry<Resource> next() {
PlanningEntry<Resource> n = pec.getPes().get(count);
count++;
return n;
}
/**
*
*
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
接下来Board实现Iterable接口
public abstract class Board implements Iterable<PlanningEntry<Resource>>{
private PlanningEntryCollection pec;
// Abstraction function:
// AF(Board)={pec | pec映射是一系列计划项}
// Representation invariant:
// nothing
// Safety from rep exposure:
// 所有变量都是private的
//
......
......
/**
* 迭代器
* @return Iterator<PlanningEntry<Resource>>
*/
@Override
public Iterator<PlanningEntry<Resource>> iterator() {
return new BoardIterator(pec);
}
}
第五章
一、高可维护性的度量与构造原则
1.高内聚,低耦合:
2.SOLID原则:
a.SRP(单一责任原则):不应有多于1个的原因使得一个类发生变化;一个类,一个责任。
b.OCP((面向变化的)开放/封闭原则):
对扩展性的开放:模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化。
对修改的封闭:模块自身的代码是不应被修改的;扩展模块行为的一般途径是修改模块的内部实现;如果一个模块不能被修改,那么它通常被认为是具有固定的行为。
用抽象方法解决。同时解决了(if/else/switch太多维护困难的问题)
c.LSP(Liskov替换原则):同第四章。
d.ISP(接口隔离原则):客户端只访问自己所需要的端口。
反面例子:
修改后:
e.DIP(依赖转置原则):抽象的模块不应依赖于具体的模块;具体应依赖于抽象。
二、面向可维护性的设计模式
1.工厂方法:
正常客户端:Product p = new ProductTwo();//通过new一个新的对象
工厂方法下:Product p = new ConcreteTwo().makeObject();//通过一个类中的方法创建对象。不暴露内部类的名字。
工厂方法:可以在ADT中也可以单独构建一个类:
Abstract Factory抽象工厂:把多个工厂方法组合到一起。
2. Proxy代理模式:隔离对复杂 对象的访问,降低难度/代价,定位在“访问/使用行为”
3.Observer模式:建立对象间一对多的情况。如偶像更新微博,所有的observer自动打印更新的行为。observer关注偶像,偶像的ADT自动将observer加入关注者名单。
4.Visitor模式:对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类。
特点:在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT。
三、面向可维护性的构造技术
1.State模式:state作为一个接口,有不同的实现类,在别的ADT执行完操作通过delegation到具体的state的实现类自动完成状态转换。
2.正则表达式:
剩下具体使用在另一篇博客有稍微详细一点的复习。
/***********************************************************************************/
以上即为软件构造复习总结3-第四、五章部分。