可维护性的相关指标
- 圈复杂度
- 代码行数
- 霍尔斯特德容积
- 可维护性置属(MI)
- 继承的层次数
- 类之间的耦合度
- 单元测试的覆盖度
模块化编程
- 高内聚
- 低耦合
- 分离关注点
- 信息隐藏
模块设计五原则
- 直接映射
- 少接口
- 小接口
- 显式接口
- 信息隐藏
内聚
所谓内聚,就是一个模块里的所有内容,是否是为了一个单一的目标而存在的?如果不是,请把他们分开。
OO设计五大原则
- 单一责任原则SRP
- 开放-封闭原则OCP
- L式替换原则LSP
- 依赖转置原则(即基于接口而不是实现编程)DIP
- 接口聚合原则ISP
单一责任原则
一个类专一于一个责任,你没有能力三心二意。
- 遇到这种情况,直接分来,使得他们专一责任。
OCP开放封闭原则
- 对拓展性的开放,即模块是可以拓展的。
- 但是同时,模块本身的代码绝对不可以修改。(可以通过继承等拓展功能)
- 解决方法:抽象,增加抽象类,使得新功能实现接口,进而增加功能,也不改变原有功能的代码。
比如上面这个例子,我们通过将shape变为接口,使得子类多态,进而clint中不再需要那么多的语句,只需要直接调用接口即可。当我们想要拓展功能时,使一个新的类implement接口Shape即可。假如不这样做,那么我们将不得不去处理那一大坨if和else:(
LSP替换原则
简单来说,为什么使用LSP,她有什么好处?通过LSP,我们可以用父类去定义,而这父类通常是个接口,提供了操作。我们client根据接口,可以处理一大堆对象。假如我们不这样做,就会导致我们不得不写一大堆if else处理不同类型的东西。而LSP中的原则定义了何时一个类能变儿子,变儿子的就能够被处理父亲程序的程序处理。所有,尽可能写符合儿子特征的程序,进而利用多态性提高复用。
ISP接口隔离原则
将一个接口类提供的接口变少,变瘦,使得每一个接口专精某一个功能,进而使得client更清晰调用接口,进而增加内聚!
举个例子,worker接口有吃和工作俩函数,现在有俩类,人和机器,都实现了这个接口,但是机器显然不能吃,因此只能空函数,这很愚蠢,不美观,为何不变成两个接口:Workable和feedable,这样人实现俩接口,机器只实现一个接口,美滋滋。
DIP依赖转置原则
通俗地讲,就是依赖接口而不是依赖实现编程。为何是转置?本来抽象类要依赖于具体类去实现,但是我们设计的时候反过来,要具体依赖于抽象,为何?
- 上层代码面向接口抽象编程,隔离了下层具体实施,这使得抽象和实现分离。
上面那个,我们直接窥到了具体的实现类。下面那个,我们写了一个接口,用接口编程。这样,我们就直接利用多态性,直接调用write方法。 - 这要求我们delegation的时候,通过Interface建立联系,而不是具体子类。这样,我们随时可以写一个新的具体子类,直接用,而不用再修改client中的代码。
语法驱动构造
- 判断终止节点:它不在产生式的左侧。叶子节点连起来就是产生的句子。
- 消除递归:host ::= host “Hello”|A可以变化为host ::= “Hello”*“A”
- 正则表达式:将所有产生式融到一个产生式,右侧全是终结符以及运算符。
- Grammar定义语法规则,Parser generator根据语法规则产生一个parser,用户利用parser解析文本,看是否符合语法定义,并对其做各种处理(比如转换成树)
- 关于转义:java中一个\代表后面的字符具有特殊意义。因此“\d*.“代表匹配数字任意个以及任何非元字符的单个字符任意次。而”\d\."代表匹配任意次数字后面加上一个点。转义两次,就变成正常的了。为了表示\,则需要四个字符串。
- 优先级:*、+、?具有最高优先级,其次是链接,最后是|。