编程基本功 (4)
数据结构与对象
数据结构
在OO世界里,数据结构往往意味着没有任何能力的纯实体,这种情况是很少见的(因为意味着纯粹数据结构的集成)。
例子:
public struct Point {
public double X {get; set;}
public double Y {get; set;}
private double x;
private double y;
}
1. 我们可以用它来存一个点,这个点可以是任何形状的一部分
2. 它不具备任何能力,仅仅是对数据的集成而已
3. 优点:修改行为容易,因为这里往往代表了数据,即便多处引用也不会影响到;缺点:修改数据结构困难,多处引用的话会影响到很多地方。
对象
对象往往和接口关系紧密,上例对应的接口示例:
public interface Point {
double getX();
double getY();
void setCartesian(double x, double y);
double getR();
double getTheta();
void setPolar(double r, double theta);
}
1. 数据被封装了
2. 暴露了一些对象的能力可以使用,但基于封装
3. 优点:由于数据结构封装了,因此修改数据结构容易;接口是一张对象能力(行为)清单,修改成本较大(open-close 原则,通常只增加接口)。
结论:
过程式设计使得修改function时无需修改数据结构(纯实体类);OO设计可以通过增加类的方式来扩展功能而无需修改已有的function。
过程式设计修改数据结构很困难,因为所有引用到的地方都要改;OO设计需改接口很麻烦因为所有相关类都要改(因此较早考虑轻量接口,开发过程只增加接口)。
避免冗长的调用
看下面这行代码:
string outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
显然如果重构一下:
string outputDir = GetAbsolutePath();
private string GetAbsolutePath(){
return ctxt.getOptions().getScratchDir().getAbsolutePath();
}
代码的意图清晰很多,调用者也方便很多。
使用抛出Exception而不是Return ErrorCode
1.ErrorCode是一个全局的level,除非确保定义的非常全面,否则一旦修改将会影响全局,而增添一个异常类比较容易
2. 容易出现重复定义
3. 异常可以使用wrapper来接触错误处理和business之间的耦合,可是使用errorcode无法解耦。
Wrapper Exception
看这段code:
try {
port.open();
} catch(DeviceResponseException e) {
reportPortError(e);
logger.log("Deviceresponse exception", e);
} catch(ATM1212UnlockedException e) {
reportPortError(e);
logger.log("Unlockexception", e);
} catch (GMXErrore) {
reportPortError(e);
logger.log("Deviceresponse exception");
}
如果多处需要调用port.open函数,那么到处都是这种catch chain。解决办法是对port进行wrap,把catch chain wrap起来:
public class LocalPort {
private ACMEPort innerPort;
public LocalPort(int portNumber) {
innerPort =new ACMEPort(portNumber);
}
public void open() {
try {
innerPort.open();
} catch(DeviceResponseException e) {
throw new PortDeviceFailure(e);
} catch(ATM1212UnlockedException e) {
throw new PortDeviceFailure(e);
} catch(GMXError e) {
109 Definethe Normal Flow
throw new PortDeviceFailure(e);
}
}
…
}
这样就使得调用的代码意图清晰很多:
try {
port.open();
} catch(PortDeviceFailure e) {
reportError(e);
logger.log(e.getMessage(),e);
}
Wrapper其实就是Adapter模式的应用之一,除了异常,还可以对第三方library以及其他API的调用进行wrap。