对象和数据结构
1 数据抽象
在对外提供的接口,我们更应坚持把数据抽象,也就是接口尽可能不要暴露其内部细节。
举个例子:
public class Point{
public double x;
public double y;
}
这样的设定,就会让外界直接知道,x,y这样的细节。从而了解到这个x,y的组成形式。可以直接对单个的值进行赋值修改。
可以改成
public interface Point{
double getX();
double getY();
void setCartesian(double x,double y);
}
这里的修改只能进行原子性的修改(x,y同时改变)。而不像上面可以只改变一个。
这里的例子是对比才会出现一种数据抽象,不暴露那么多细节的概念。我们也可以通过举其他的例子。
举个例子:要获取一个点坐标。
public interface Point{
double getX();
double getY();
}
这里通过分别获取X,Y的值来组成一个点的坐标。
public interface Point{
Point getPoint();
}
也可以通过一个方法直接获取点的坐标,这里就是getPoint
方法里面封装了getX
,getY
的操作,从而又减少了形成坐标的细节。
2 数据结构与对象的对立之处
先举上面的例子:
public class Point{
public double x;
public double y;
}
这是数据结构。
public interface Point{
double getX();
double getY();
void setCartesian(double x,double y);
}
这是对象。
数据结构,暴露具体的数据定义,而不暴露函数。
对象提供具体的函数,而不提供具体的数据定义。
这里面存在一个对象与数据结构之间的二分原理:
使用数据结构的代码便于不改动既有数据结构的前提下添加新函数。
面向对象便于不改动既有函数的情况下添加新函数。
从这里也可以得到一个结论:
使用数据结构的代码不便于添加新的数据结构,因为要修改很多函数。
使用面向对象的难以添加新函数,因为要修改所有类。
先举数据结构代码添加新数据结构的例子:
public class Point{
public double x;
public double y;
public double z; //新添加z
}
那么这个时候原先需要赋值的函数就还需要对z进行赋值,如果有需要的话。还有取值等其他函数,都得考虑是否需要为新添加的改变函数。
再举面向对象代码添加新函数的例子:
public interface animal{
public void eat();
public void sleep(); //新增加sleep方法
}
这里新增了sleep()
方法,从而使得所有实现animal接口的类都要添加这个方法。本来是想举继承的例子的。但是接口代码少一点!
3 得墨忒耳律
得墨忒耳律认为:模块不应了解它所操作对象的内部情形。
这里书上说了有通过存取访问属性会暴露对象的内部结构这点是得墨忒耳律不认可的。因为属性存取器反而会暴露内部的结构。
它只支持 类的方法 只能调用 以下对象的方法 :
- 类对象。
- 由该方法本身创建的对象。
- 作为参数传递给该方法的对象。
- 该类创建的实体对象能使用的对象。
保留意见,继续看书。
3.1 火车失事
这里是指那些不断引用新方法的代码行。
举个例子:
user.getNewUser().getUserName().ToString();
应该尽量把它拆分成几个函数来赋值。
3.2 混杂
在了解道二分原理之后,我们也可以得知,我们平时写的代码是否会出现,使用数据结构和面向对象的代码,五五开的情况,或者是没有规划,随心而动随手写下糟糕的代码。
这种混杂的代码就会导致,维护起来很麻烦,如果要进行添加修改的话就要改动很多地方。
3.3 隐藏结构
这里的隐藏结构是说的可以尽可能的优化代码逻辑,减少内部结构的暴露。
举个例子:
user.getNewUser().getUserName().ToString();
这里的代码是为了打印出默认的用户名字。
我们可以进行修改,不要套这么多层。
user.PrintDefaultName();
这样就可以进一步隐藏函数内部结构。
4 数据传送对象
就是只有公共变量、没有函数的类。有时会被叫为数据传输对象(Data Transfer Objects,简称:DTO)。
在数据库通信、解析套接字传递的消息之类场景之中很有用!
也有将这种对象进行一定程度的修改,将公共变量改成私有变量,再添加属性存储器(getter
,setter
)。也就是bean
结构。
Active Record 也是特殊的DTO形式。有公共变量的同时保存着一些类似find
或save
形式的可浏览方法。
但是最好不要往Active Record这种数据解耦里面塞入业务规则方法,这样会导致维护起来麻烦。可以再套一层,让它做数据结构,然后创建业务规则。
5 小结
对象隐藏数据,暴露行为。便于添加新对象类型不修改行为,难于在已有对象添加新行为。
数据结构暴露数据,无明显行为。便于添加新行为,难于添加新数据结构。
在使用的时候应该尽可能的根据特点考虑好要如何进行编码。