This series, The Object-Oriented Thought Process, is intended for someone just learning an object-oriented language and wants to understand the basic concepts before jumping into the code or someone who wants to understand the infrastructure behind an OOP language they are already using. Click here to start at the beginning of the series.
In keeping with the code examples used in the previous articles, Java will be the language used to implement the concepts in code. One of the reasons that I like to use Java is because you can download the Java compiler for personal use at the Sun Microsystems Web site http://java.sun.com/. You can download the J2SE 1.4.2 SDK (software development kit) to compile and execute these applications and I will provide the code listings for all examples in this article. I have the SDK 1.4.0 loaded on my machine. I will also provide figures and the output (when appropriate) for these examples. See the previous articles in this series for detailed descriptions for compiling and running all the code examples in this series.
An Object Must be Responsible for Itself
One of the most important mantras used in object-oriented design is that of "an object must be responsible for itself". I first heard this phrase while taking my first class in object-oriented programming class in Smalltalk. Because I had never programmed in an object-oriented language before, I was curious as to what this really meant.
While there are many ways to approach this point, it really boils down to the concept of encapsulation, just as everything does when dealing with properly designed classes. The whole concept of an object is that it contains both attributes and behaviors. In structured programming, there is code and there is data, and the two are thought of as separate entities. The power of an object is that these two separate entities are encapsulated together to form a single, atomic entity. It is in this fundamental concept of an encapsulated, atomic entity that you come to realize how and why an object is responsible for itself.
A straightforward definition for object-responsibility is this: An object must contain the data (attributes) and code (methods) necessary to perform any and all services that are required by the object. This means that the object must have the capability to perform required services itself or at least know how to find and invoke these services. Rather than attempt to further refine the definition, take a look at an example that illustrates this responsibility concept.
An Internet Example
Consider a simple banner (a Java object/applet) that is placed at the top of a web page. The banner is a basic rectangle which cycles through multiple text messages. The banner contains several attributes such as the background color of the banner, the color of each of the messages, the size of the rectangle, and so forth. The banner also contains at least one method, the code that controls the fading in and out of the various messages.
This Java object is invoked by HTML code in the Web page, the code might look something like this:
<object code="banner.class" width="600" height="70">
The important thing to note here is that everything in the object is contained neatly in the class file. As stated above, "banner.class" includes all the attributes and all the code that is necessary for the banner to execute properly.
To further understand the power of encapsulation, it is important to realize that "banner.class" is, most likely, physically located somewhere on the Internetnot on the local machine. The implication is that while the browser can invoke the banner object, it has no idea what to do with itit simply loads it. In short, the browser is not responsible for any functionality of the banner object. The banner object is responsible for itself. Any functionality (services) that the banner must deliver, the banner must perform and manage itself.
One question that may come up is this: if the banner object is totally self contained, how can the Web page communicate with the object? There may be some basic functionality that the banner performs that requires no information; however, consider that different Web pages may want to use the same banner object. It is likely that each of the sites will want to display different messages and set the banner attributes differently. For example, one site may want the banner background to be red, while another may want the banner background to be blue. The answer to this is simple: parameters are used to convey information from a specific Web page to the object invoked by that page. Thus, we can get unique information into a self-contained object.
An Application Example
While the Internet provides a good example as to how self-contained objects are used, we can also consider standalone application when looking for an example to illustrate object responsibility. One of my favorite examples is that of a generic paint program. No doubt that everyone has used a basic drawing program that allows a user to select a shape from a pallet and then drag it to a canvas, where the shape is dropped and displayed. From the user's perspective, this activity is accomplished by a variety of mouse actions. First, the user hovers over a specific shape with the mouse (perhaps a circle), right clicks, drags the shape to a location on the canvas and then lifts his/her finger off the mouse.
This last action causes the shape to be placed at the desired location. In fact, what is really happening when our user's finger is lifted from the mouse button? We can use this action to illustrate our object responsibility concept. Let's assume that when the finger is lifted from the mouse button that the resulting message from this event is simply: draw. Consider the mouse as an object and that the mouse is only responsible for itself as well. The mouse can, and should only do mouse things. In this context, when the finger is lifted from the mouse button, the mouse thing to do is to draw. But draw what? Actually, the mouse doesn't care. It is not the mouse's responsibility to know how to draw anything. Its responsibility is to signal when to draw, not what to draw.
If this is the case (remember that a circle was selected), how does the right thing get drawn? The answer is actually pretty straightforward; the circle knows how to draw itself. The circle is responsible for doing circle thingsjust like the mouse is responsible for doing mouse things. So, if you select a circle, the circle object that is created knows everything possible about how to use a circle in the application.
This model has a major implication. Because the mouse does not need to know anything about specific shape objects, all it needs to do to draw a shape is to send the message draw. Actually, this will take the form of a method called draw( ). Thus, more shapes can be added without having to change any of the mouse's behavior. The only constraint is that any shape object installed in the application must implement a draw( ) method. If there is no draw( ) method, an exception will be generated when the mouse mouse-up action attempts to invoke the object's non-existent draw( ) method. In this design methodology, there is a de facto contract between the mouse class and the shape class and these contracts are made possible by the powerful object-oriented design technique called polymorphism.