哈尔滨工业大学软件构造心得(五)

目录

1. 面向复用的软件构造技术

1.1复用的类型

1.2 LSP

1.3 委托(Delegation)

2. 面向可维护性的软件构造技术

2.1 可维护性度量指标

2.2 SOLID设计原则

2.3 正则表达式


1. 面向复用的软件构造技术

1.1复用的类型

软件复用:最主要的是代码复用,但也有其他方面。

Source code level:methods, statements, etc Module level:class and interface Library level:API Architecture level:framework

白盒复用:源代码可见、可修改和扩展(对应继承)

黑盒复用:源代码不可见,不能修改,只能通过API接口使用(对应委托)

代码复用
即直接复制代码(不推荐)

类的复用
inheritance 继承 delegation 委托

继承能做的事委托也能做,继承要求严格父子关系

框架(framework)
框架:一组具体类、抽象类、及其之间的连接关系

开发者根据framework的规约,填充自己的代码进去,形成完整系统

API和框架的区别:主控端在用户/框架

1.2 LSP

子类型多态:客户端可以用统一的方式处理不同类型的对象。

LSP原则
能被Java静态类型检测检测出的:

子类型可以增加方法,但不可以删除方法
子类型需要实现抽象类型中的所有未实现的方法
子类型中重写的方法必须返回相同的类型或者子类型(满足协变)
子类型中重写的方法必须使用同样类型的参数(或符合逆变的参数)
子类型中重写的方法不能抛出额外的异常(协变)
不能被静态类型检测出的:

更强的不变量
更弱的前置条件
更强的后置条件(与上条综合即规约更强)
协变:父类型->子类型:越来越具体

反协变(逆变):越来越抽象

注意:Java不支持反协变!Java识别其为重载(而非重写)

数组满足协变。

泛型中的LSP
泛型不满足协变 List<String>不是List<Object>的子类型

Object是所有泛型的父类,List<?>是List<Object>的父类

1.3 委托(Delegation)

Interface Comparator< T >
int compare(T o1, T o2): Compares its two arguments for order

如果你的ADT需要比较大小,或者要放入Collections或Arrays进行排序,可以实现Comparator接口并且override compare()函数

另一种方法:让ADT实现Comparable接口,然后override compareTo() 方法

与使用Comparator的区别:不需要构建新的Comparator类,比较代码放在ADT内部

委托
委托/委派:一个对象请求另一个对象的功能。

如果子类只需要复用父类中的一小部分方法,可以通过委托机制调用。

委托是复用的一种常用形式。(CRP原则:尽量使用委托进行复用)

Use 使用:通过方法的参数传递(use_a)
Association 关联:通过类的属性传递(has_a)

class B{
    void b(A a){  //use 使用
        ...    
    }
}

class B{
    A a; //Association 关联
    ....
}

composition/aggregation 组合/聚合(可认为是Association的两种具体形态)

聚合运行时可更改绑定对象(较弱的关联)

聚合B类销毁时,A类可能不会销毁(可能还有指向其的指针);组合B类销毁时,A类同时被销毁

2. 面向可维护性的软件构造技术

2.1 可维护性度量指标

圈复杂度(Cyclomatic Complexity)、代码行数、可维护性指数(MI)、继承的层次数、类之间的耦合度、单元测试的覆盖度

模块化编程
高内聚(High cohension) 低耦合(Low coupling)

耦合(Coupling):不同模块之间的相互依赖性

内聚(Cohension):模块内功能和职责的一致性

耦合和内聚之间的权衡:即不能同时高/同时低

2.2 SOLID设计原则

SRP(单一责任原则)
OCP(开放-封闭原则)
LSP(Liskov替换原则)
DIP(依赖转置原则)
ISP(接口聚合原则)

SRP(单一责任原则)

把类拆分,使得每个类只完成一个功能。(不应该有多于一个的原因使得类发生变化)

SRP是最简单的原则,却是最难做好的原则

OCP(开放/封闭原则)
对扩展性的开放:模块的行为应该是可扩展的

对修改的封闭

关键的解决方案:抽象技术

例:如果有多种类型的Server,那么针对每一种新出现的Server,不得不修改Server类的内部具体实现;

通过构造一个抽象的Server类:AbstractServer,该抽象类中包含针对所有类型的Server都通用的代码,从而实现了对修改的封闭;当出现新的Server类型时,只需从该抽象类中派生出具体的子类ConcreteServer即可,从而支持了对扩展的开放。

LSP(Liskov替换原则)

ISP(接口隔离原则)
尽量和专用接口连接(客户端不应依赖于它们不需要的方法)

DIP(依赖转置原则)
尽量依赖抽象类而不是具体类

也就是delegation的时候,通过interface来建立联系,而非具体子类

2.3 正则表达式

*:重复0-多次

|:选择 a|b

?:0次或1次 x ::= y ? x为y或空串

[a-c]:‘a’ | ‘b’ | ‘c’

[^a-c]:‘d’ | ‘e’ | ‘f’ …(相当于补)

正则语法(Regular grammar)
正则语法:简化之后可以表达为一个产生式而不包含任何非终止节点

正则表达式:左侧为非终结符,右侧没有非终结符

注意有的字符需要进行转义

Java中的正则表达式
Pattern是对regex正则表达式进行编译之后得到的结果

Matcher:利用Pattern对输入字符串进行解析

Matcher对象只能通过Pattern静态方法创建,不能new
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值