Tuesday, July 13, 2004

OOP: Information Hiding

While Java has ushered in a number of beneficial programming constructs, it has also undermined good object-oriented design approaches. As an example, consider the basic Java Bean. I'm not talking about Enterprise Java Beans but just plain old Beans.

A Bean has a simple mission in life...allow other code to get and set properties without knowing anything about the object or its internal structure. Java accomplishes this through its reflection APIs by using a simple, predictable Bean method signature. Commonly, the Bean methods directly correspond to private data members in the Bean class, however the JavaBeans specification does not require this practice.

Unfortunately, most programmers do not know and/or do not care about the specification. As a direct result, programmers often implement most data objects as beans. When the object consists of nothing more than primitive types such as int and String, I have no problem. It is when the object consists of non-primitive data types where I cry foul.

Why? It's simple Java pass-by-value programming, something most programmers fail to understand even at a reasonably advanced level.

When you return a primitive data type or pass it as a parameter, Java makes a copy of the data and sends the copy. However, when you work with non-primitive types (i.e. List, Stack, etc.), Java makes a copy of the reference to the object. While it is a subtle distinction, it is an extremely important one.

Consider the following code:

public class Example {
private int a;
private Vector b;
public int getA() { return a; }
public Vector getList() { return list; }

If your code calls example.getA() and modifies the result, the private member within example does not change. However, if your code calls example.getList() and calls addElement on the returned Vector, the Vector b within example DOES change. Consequently, the calling code becomes dependent on the private member type.

Java offers a variety of means by which this situation can be prevented. Cloning often works out to be the easiest approach. It keeps the simple structure of the bean-style programming, but it prevents programmers from relying on the underlying private member type by presenting them with a copy, much like Java already does for primitive data types (remember that String is a primitive type...tough one for a C++ programmer).

Self-discipline might....err....nevermind...

Ultimately, the goal is more easily maintained code. If you expose private data, you run the risk of making a black box transparent. What happens when that Vector needs to change to a Hashtable to provide faster access. All of those callers relying on example.getList().addElement( "hello world" ) will break. What do you do now that those calls are littered throughout several thousand lines of code?



Post a Comment

<< Home