artima.com

Chapter 1 of API Design
The Object
by Bill Venners

Part 5 of 21

Advertisement

Guideline 2. See objects as bundles of behavior, not bundles of data

One of the most basic object-oriented ideas is encapsulation -- associating data with code that manipulates the data. The data, stored in instance variables, represents the object's state. The code, stored in instance methods, represents the object's behavior. Because of encapsulation, therefore, you can think of objects as either bundles of data, bundles of behavior, or both. To reap the greatest benefit from encapsulation, however, you should think of objects primarily as bundles of behavior, not bundles of data. You should think of objects less as carriers of information, embodied in the data, and more as providers of services, represented by the behavior.

Why should you think of objects as bundles of services? If data is exposed, code that manipulates the data spreads across the program. If higher-level services are exposed, code that manipulates the data concentrates in one place: the class. This concentration reduces code duplication, localizes bug fixes, and helps you achieve robustness.

A Data-Oriented Matrix

Consider the Matrix class shown in Diagram 2-1. Instances of this Matrix class act more like bundles of data than bundles of behavior. Although the instance variables declared in this class are private, the only services it offers besides equals, hashcode, clone, and toString are accessor methods set, get, getCols, and getRows. These accessor methods are data oriented. They do nothing interesting with the object's state; they merely provide clients access to that state.

Diagram 2-1. A data-oriented Matrix

com.artima.examples.matrix.ex1
Matrix
public class Matrix implements java.io.Serializable, Cloneable
    Represents a matrix each of whose elements is an int.
Constructors
public Matrix(int rows)
    Construct a new square zero matrix whose order is determined by the passed number of rows.
public Matrix(int rows, int cols)
    Construct a new zero matrix whose order is determined by the passed number of rows and columns.
public Matrix(int[][] init)
    Construct a new Matrix whose elements will be initialized with values from the passed two-dimensional array of ints.
Methods
public Object clone()
    Clones this object.
public boolean equals(Object o)
    Compares passed object to this Matrix for equality.
public int get(int row, int col)
    Returns the element value at the specified row and column.
public int getCols()
    Returns the number of columns in this matrix.
public int getRows()
    Returns the number of rows in this matrix.
public int hashcode()
    Computes the hash code for this Matrix.
public void set(int row, int col, int value)
    Sets the element value at the specified row and column to the passed value.
public String toString()
    Returns a String that contains the integer values of the elements of this Matrix.

Listing 2-1 shows Example1, a client of the data-oriented Matrix. This client adds two matrices and prints the sum to the standard output.

Listing 2-1. A client of the data-oriented Matrix

package com.artima.examples.matrix.ex1;

class Example1 {

    public static void main(String[] args) {

        int[][] init1 = { {2, 2}, {2, 2} };
        int[][] init2 = { {1, 2}, {3, 4} };

        Matrix m1 = new Matrix(init1);
        Matrix m2 = new Matrix(init2);

        // Add m1 & m2, store result in a new Matrix object
        Matrix sum = new Matrix(2, 2);
        for (int i = 0; i < 2; ++i) {
            for (int j = 0; j < 2; ++j) {
                int addend1 = m1.get(i, j);
                int addend2 = m2.get(i, j);
                sum.set(i, j, addend1 +  addend2);
            }
        }

        // Print out the sum
        System.out.println("Sum: " + sum.toString());
    }
}

To add the matrices, Example1 first instantiates a matrix to hold the sum. Then for each row and column, Example1 invokes get on each addend matrix, adds the two returned values, and enters the result into the sum matrix using set.

This all works fine, but imagine you need to add matrices at 50 different places in your code. Example1 requires eight lines of code to add two matrices, shown highlighted in Listing 2-1. You would need to repeat those eight lines of code, or something similar, at 50 different places in your code. Perhaps the code performs flawless matrix addition in 46 of those places, but the other four places contain bugs. If you detect and fix a bug in one of those four places, you still have three matrix addition bugs lurking elsewhere.

Part 5 of 21

API Design | Contents | Book List | Printer Friendly Version | Previous | Next

Last Updated: Friday, April 26, 2002
Copyright © 1996-2002 Artima Software, Inc. All Rights Reserved.
URL: http://www.artima.com/apidesign/object5.html
Artima.com is created by Bill Venners