Code references are to: OOP Example code: Expressions
Find it on a single page here
sumExpressions
, there are three objects named one
, two
and sum
, and we send the “message” getValue
to the object sum
when we write sum.getValue()
.Encapsulation is the property that an object’s data can only be altered by calling the object’s methods. This allows us to control essential internal properties of the object, and can be certain that noone can mess with those properties. You can think of objects a bit like biological cells, where the inner parts are safely protected against outside influence, and the only way to effect a change is by interacting via specific processes on the cell’s membrane.
Information hiding is the property of protecting internal implementation details from being seen from other parts of the application, for example, by declaring data fields and methods to be private. Someone looking at a cell can’t really tell what the cell is made of.
SumExpression
’s business.Message passing is how objects communicate with each other. They pass messages to each other telling them to do something. This is an essential element of object-oriented-programming:
In object-oriented method calls / message passing, the sender sends a message to a receiver, and the two sides are very loosely coupled to each other. The receiver does not know who sent them the message, and the sender has no idea how the receiver will handle that message.
As an example of this, consider the getValue
implementation of the SumExpression class:
public int getValue() {
return term1.getValue() + term2.getValue();
}
Here term1
and term2
are Expression
objects, and we call their getValue
method. These could be IntegerExpression
objects or SumExpression
objects; we don’t know, and we don’t care. We are simply asking them to respond to the getValue
message. Objects of different classes will likely respond in different ways.
Every operation is characterized by a name, the kinds of objects it takes as arguments, and the kind of value it returns. These elements collectively are the signature of the operation. As an example, the getValue
method takes no arguments, and returns an integer.
The collection of all the signatures for the operations that an object can handle is the object’s interface.
A collection of signatures is called a type. We say that an object has a type if it has an implementation for each operation specified in the type.
In Java we can express such types via the formal element called a Java Interface.
Interfaces specify what an object can do, and NOT how to do it. The latter is the job of classes.
Objects can have the same interface/type, but different implementations. A call like o.draw()
sends the draw
message to the o
object. Therefore o
must implement an interface that contains a draw
method, but we don’t know what specific implementation of draw
is executed until runtime. At runtime, the implementation of draw
that the specific object o
has will be executed. This is known as dynamic binding, also some times referred to as late binding.
Dynamic binding allows us to write programs based on an object’s interface, then swap objects at runtime, as long as they have the same interface. This allows us to vary the implementation without changing the code, so that the result of o.draw()
can vary depending on which specific method is executed. This ability to substitute an object with a given interface for another object with the same interface is called polymorphism.
Example: We can define two different classes for “points”: A XYPoint
class, which defines a point via its x,y coordinates, and a PolarPoint
class, which defines a point via polar coordinates, namely the distance r
from the origin and the angle theta
that the point forms with the x-axis. But both points have a getX()
method that returns the x coordinate of the point. For the XYPoint
instances it simply returns the stored x
value, for the PolarPoint
instances in computes r * Math.cos(theta)
. Both classes implement the same Point
interface. A user who has received an object that implements the Point interface knows that they can do p.getX()
, but they don’t know nor care whether it is the XYPoint
’s method that gets executed or the PolarPoint
’s method.
Such a user can for example be given two points p1
and p2
, and can compute their x
-distance by doing p1.getX() - p2.getX()
, without needing to know whether the points are both XYPoint
instances, or both PolarPoint
instances, or one of each, or some competely different kind of points altogether.
default
keyword does allow these methods, you should be hesitant in their use).