数据抽象
隐藏实现不仅仅是在变量之间放置一层函数。隐藏实现是关于抽象的! 一个类不仅仅通过getter和setter将其变量推出去。相反,它公开抽象接口,允许用户操纵数据的本质,而无需知道其实现。
数据/对象反对称性
这两个示例展示了对象和数据结构之间的区别。对象在其数据背后隐藏抽象,并公开操作该数据的函数。数据结构公开其数据,并且没有有意义的函数。
过程式形状
public class Square {
public Point topLeft;
public double side;
}
public class Rectangle {
public Point topLeft;
public double height;
public double width;
}
public class Circle {
public Point center;
public double radius;
}
public class Geometry {
public final double PI = 3.141592653589793;
public double area(Object shape) throws NoSuchShapeException {
if (shape instanceof Square) {
Square s = (Square)shape;
return s.side * s.side;
}
else if (shape instanceof Rectangle) {
Rectangle r = (Rectangle)shape;
return r.height * r.width;
}
else if (shape instanceof Circle) {
Circle c = (Circle)shape;
return PI * c.radius * c.radius;
}
throw new NoSuchShapeException();
}
}
多态形状
public class Square implements Shape {
private Point topLeft;
private double side;
public double area() {
return side * side;
}
}
public class Rectangle implements Shape {
private Point topLeft;
private double height;
private double width;
public double area() {
return height * width;
}
}
public class Circle implements Shape {
private Point center;
private double radius;
public final double PI = 3.141592653589793;
public double area() {
return PI * radius * radius;
}
}
再次,我们看到了这两种定义的互补性质;它们几乎是对立的! 这暴露了对象和数据结构之间的根本二分法:
过程式代码(使用数据结构的代码)使添加新函数而不改变现有数据结构变得容易。另一方面,面向对象的代码使添加新类而不改变现有函数变得容易。
补充也是正确的:
过程式代码使添加新的数据结构变得困难,因为所有函数都必须改变。面向对象的代码使添加新函数变得困难,因为所有类都必须改变。
成熟的程序员知道,一切都是对象的想法是一个神话。有时你确实想要简单的数据结构,让过程在它们上操作。
迪米特法则
有一个著名的启发式法则叫做迪米特法则,它说一个模块不应该了解它操作的对象的内部结构。
更准确地说,迪米特法则表明,一个类 C
的方法 f
只应该调用以下对象的方法:
C
- 由
f
创建的对象 - 作为参数传递给
f
的对象 - 由
C
的实例变量持有的对象
该方法不应该调用任何允许函数返回的对象上的方法。换句话说,与朋友交谈,而不是与陌生人交谈。
数据传输对象
数据结构的典型形式是一个具有公共变量和没有函数的类。这有时被称为数据传输对象,或DTO。DTOs是非常有用的结构,特别是与数据库通信或解析来自套接字的消息等时。它们经常成为一系列转换阶段中的第一个,这些阶段将数据库中的原始数据转换为应用程序代码中的对象。