一、Programing for/with reuse
不仅Programing for reuse(面向复用编程:开发出可复用的软件)代价高,Programing with reuse(基于复用编程:利用已有的可复用软件搭建应用系统)也高。
其开发成本会更高——要有足够高的适应性,性能也会差些——没有针对性。
最主要的复用是在代码层面,但软件构造过程中的任何实体都可能被复用(下图为几个层面的复用)
可复用的代码很多,最重要的是自己日积月累的
白盒复用:源代码可见,可修改和扩展;黑盒复用:源代码不可见,不能修改
框架层面的复用中:白盒框架,通过代码层面的继承进行框架扩展;黑盒框架,通过实现特定接口/delegation进行框架扩展
二、LSP、协变,反协变、通配符(?)
个人的一些理解:规约强度变强,父能做的子也要能做,子要比父强,子不能做违背祖宗的事
协变,反协变:
协变:父类型→子类型:越来越具体specific;一般是返回值、异常类型:不变或变得更具体
反协变:父类型→子类型:越来越具体specific;一般是参数类型:要相反的变化,要不变或越来越抽象(当作overload对待)
泛型中的通配符(?):下限用super(可匹配他的各种父类),上限用extend(可匹配他的各种子类),有无界通配符,一般用于定义一个引用变量,其可以指向多个不同类型的变量。eg:?extend number可匹配int,double等
三、Comparator和Comparable
这两是用来比较ADT大小的。Comparator是一个外部接口,可用以委派,一般建一个类来实现该接口。Comparable是需要比较的类本身实现的一个接口
若是前者就重写Compare方法,后者重写CompareTo方法
四、委托/委派(Delegation)、CRP
其是一个对象请求另一个对象的功能,是复用的一种常用形式
一个例子:
构建时绑定一个类,之后便可以使用其功能
“委托”发生在object层面,而“继承”发生在class层面,CRP原则更倾向于使用委派而不是继承来实现复用。
对于接口:接口之间可以继承和扩展
五、可维护性的常见度量尺标、聚合度和耦合度、SOLID
度量尺标有圈复杂度,代码行数,可维护性指数,继承的层次数,类间耦合度,测试覆盖度等等
设计时应尽量低耦合和高内聚
SOLID:
简单来说就是:不应该有多于1个原因让你的ADT发生变化,否则就拆分开;对扩展性的开放,对修改封闭(抽象类运用);LSP;只提供必要的接口;抽象的模块不应依赖于具体的模块)
六、语法、正则表达式
边界匹配器:^ 代表以某些内容开头;$ 代表以某些内容结尾
eg: "^[a-z][0-9]$"
数量词:所有数量词都是放在元素之后的
X? 代表出现0或1次;X* 代表出现次数大于等于0次;X+ 大于等于1;
X{n} 代表出现n次;X{n,} 代表至少出现n次;X{n,m} 代表次数在之间
逻辑运算符:“|”或
特别的:
\\d:相当于[0-9];\\t:制表符;\\\\:斜线字符\\;\\.:.;\\n:换行符;\\r:回车符
.:任意一个字符;[xxx]:匹配括号内任意一个;[^abc]:^表示除所修饰字符以外的其他字符
七、设计模式(重难点,详细看PPT复习)
简单说说:
1、Factory Method pattern工厂模式:比较简单的方法,包括静态工厂
2、适配器模式:适配器实现一个接口,客户端调用这个接口,调用适配器,同时,适配器中的实现来自于适配器内部,而适配器本身作为一个类,它的方法可以继承复用一个父类的方法或者委托复用一个其他类的方法。
通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。
3、装饰器模式:将通用实现委托给已有实现,为对象增加不同侧面的特性,对每一个特性构造子类,通过委派机制增加到对象上
4、策略模式:算法的不同实现,为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例
5、模板模式:做事情的步骤一样,但具体方法不同,共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现——使用继承和重写实现模板模式
6、Iterator迭代器:提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
7、visitor:对特定类型的object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类;
为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT