Objects and Data Structures

Objects and Data Structures

Data Abstraction

Hiding implementation is not just a matter of putting a layer of functions between the variables. Hiding implementation is about abstractions! For example on the following excerpt we do not know how the Point is defined, if by rectangular coordinates or by polar coordintes.

public interface Point {
  double getX();
  double getY();
  void setCartesian(double x, double y);
  double getR();
  double getTheta();
  void setPolar(double r, double theta);
}

Data/Object Anti-Symmetry

Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions. They are virtual opposites.

Procedural Shape

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();
  }
}

Polymorphic Shapes

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;
  }
}

This exposes the fundamental dichotomy between objects and data structures: Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.

In any complex system there are going to be times when we want to add new data types rather than new functions. For these cases objects and OO are most appropriate. On the other hand, there will also be times when we’ll want to add new functions as opposed to data types. In that case procedural code and data structures will be more appropriate.

The Law of Demeter

The Law of Demeter says a module should not know about the innards of the objects it manipulates. More precisely, the Law of Demeter says that a method f of a class C should only call the methods of these:

  • C
  • An objects created by f
  • An Object passed as an argument to f
  • An object held in an instance variable of C

That is, the method should not invoke methods on objects that are returned by any of the allowed functions.

Hybrids

The are structures that are hybrid structures which are half object and half data structure. They have functions that do significant things, and they also have either public variables or public accessors and mutators that make the private variables public.

Such hybrids make it hard to add new functions but also make it hard to add new data structures.

Data Transfer Objects

The quintessential form of a data structure is a class with public variables and no functions. This is sometimes called a data transfer object, or DTO. They are useful when communicating with databases or parsing messages from sockets, and so on and one should avoid adding business logic to these type of objects.

Active Record

Active Records are special forms of DTOs. They are data structures with public variables; but they typically have navigational methods like save and find. Typically these Active Records are direct translations from database tables, or other data sources.

We should treat the Active Record as a data structure and to create separate objects that contain the business rules and that hide their internal data.

Conclusion

Objects expose behavior and hide data. This makes it easy to add new kinds of objects without changing existing behaviors. It also makes it hard to add new behaviors to existing objects. Data structures expose data and have no significant behavior. This makes it easy to add new behaviors to existing data structures but makes it hard to add new data structures to existing functions.