by Richard Taylor : 2019-06-25
One of the problems that I have with "Object Oriented Programming" is that the word "Object" itself can send people down the wrong path. Because we learn at school that sentences have a "subject + verb + object" structure, we are likely to be biased towards thinking of an "object" as a thing that something happens to.
Instead I like to think of an Object as representing a Concept. Any kind of concept - a thing, an action or a relationship.
Let's take a simple example from geometry of a two-dimensional point. We can represent a point with an object. The object can contain data and it can have methods.
Point p = new Point(1, 2); Point q = new Point(1, 3); float d = p.distanceTo(q);
This style of OOP is sometimes called "ask don't tell". All the data is hidden in the Point object and we ask it to compute things instead of getting the data out to compute things ourselves.
Which is fine if we know all the questions that an object might be asked, or if we are happy to always add new methods for new questions.
float e = p.euclideanDistanceTo(q); float m = p.minkowskiDistanceTo(q); // what does the original p.distanceTo(q) do now?
But then you also have to decide whether to remove old methods that might no longer have a clear function... but may be in wide use by other code.
Sometimes you start with a very well defined, small, concept that will never be extended. So you go with "ask don't tell" and everything is fine. Until the concept does need to be extended after all.
In the Point example above we assumed that a distance was a simple number and that there was only one way to calculate the one true distance between points.
But distance is a concept, so we could have a Distance object instead.
Point p = new Point(1, 2); Point q = new Point(1, 3); Distance d = new Distance(p, q);
And then we can extend that concept without changing the Point concept.
Distance e = new EuclideanDistance(p, q); Distance m = new MinkowskiDistance(p, q);
Also, we can express a distance between Point and Line objects...
Line line = new Line(p, q); Distance d = new EuclideanDistance(p, line);
Whereas with "ask don't tell" you have to choose to add the distance method to either the Point object or the Line object, or both?
// a equals b float a = p.distanceTo(line); float b = line.distanceTo(p);
When it comes to actions, it is common to think of the thing performing the action as an object, with the action then being a method.
Object obj = getSuspect(); Validator v = getValidator(); Boolean b = v.validate(obj);
Sometimes it is neater to represent the action itself as an object; especially if the action has multiple properties:
Object obj = getSuspect(); Validate v = new Validate(obj); Boolean b = v.asBoolean(); List<String> gripes = v.errors();
And action objects make a lot of sense if you are dealing with a set of related actions. For example, if you have a robot that can execute different types of movement, then representing each movement as an object seems quite natural:
Robot mickey = new Robot("Mickey"); List<Move> moves = getPreMoves(); moves.add(new Turn(90)); moves.add(new Walk(20)); mickey.do(moves);
In "object oriented programming" it is easy to see how objects can be used to represent "things" such as:
But it is less obvious to see that objects can also represent relationships:
Actions can also be represented by objects:
And the real power of OOP comes when objects are used to represent all of these different types of concepts, not just the "things".