artima.com

Chapter 1 of API Design
The Object
Guideline 2. See objects as bundles of behavior, not bundles of data
by Bill Venners

Part 6 of 21

A Service-Oriented Matrix

Now consider Diagram 2-2, which you can consider a second iteration in the design of class Matrix. In this iteration of Matrix, the previous iteration's set method has been replaced by more service-oriented methods: add, subtract, and multiply.

Diagram 2-2. A service-oriented Matrix

com.artima.examples.matrix.ex2
Matrix
public class Matrix implements java.io.Serializable, Cloneable
    A two-dimensional matrix of ints.
Constructors
public Matrix(int rows)
    Construct a new square 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 Matrix add(Matrix addend)
    Adds the passed Matrix to this one.
public Object clone()
    Clones this object.
public boolean equals(Object o)
    Compares passed Matrix 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 Matrix multiply(int scalar)
    Multiplies this matrix by the passed scalar.
public Matrix multiply(Matrix multiplier)
    Multiplies this Matrix (the multiplicand) by the passed Matrix (the multiplier).
public Matrix subtract(Matrix subtrahend)
    Subtracts the passed Matrix from this one.
public String toString()
    Returns a String that contains the integer values of the elements of this Matrix.

The data required for matrix addition sits inside instances of class Matrix in the elements instance variable. In this second iteration, the code that performs matrix addition has moved to the class that contains the data. In the previous iteration, this code existed outside class Matrix, as demonstrated by the Example1 client of Listing 2-1. This code now shows up in the Matrix class's add method, shown in Listing 2-2.

Listing 2-2. The add method of the service-oriented Matrix

package com.artima.examples.matrix.ex2;

//...

public class Matrix implements Serializable, Cloneable {

    private int[][] elements;

    //...

    public Matrix add(Matrix addend) {

        int rowCount = getRows();
        int colCount = getCols();

        // Make sure addend has the same order as this matrix
        if ((addend.getRows() != rowCount)
            || (addend.getCols() != colCount)) {

            throw new IllegalArgumentException();
        }

        Matrix retVal = new Matrix(elements);
        for (int row = 0; row < rowCount; ++row) {
            for (int col = 0; col < colCount; ++col) {
                retVal.elements[row][col] += addend.elements[row][col];
            }
        }
        return retVal;
    }

    //...
}

Moving the addition code to the Matrix class means clients need not perform the add service themselves. Instead, clients can ask the Matrix object to perform that service for them. Clients can now delegate responsibility for matrix addition to Matrix, the class that has the data required for addition.

For example, consider the Example2 client shown in Listing 2-3. Example2 performs the same function as Example1: it adds two matrices and prints the result. But Example2 is a client of the service-oriented Matrix.

Listing 2-3. A client of the service-oriented Matrix

package com.artima.examples.matrix.ex2;

class Example2 {

    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 = m1.add(m2);

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

Now if you must add matrices at 50 places in your code, you need only repeat Example2's one liner, shown highlighted in Listing 2-3. If you discover a bug in matrix addition that corrupts matrix data, you know where to look: the add method of class Matrix. Once you fix that bug, it is in effect fixed at all 50 places where your code performs matrix addition. This is how seeing objects as bundles of services, not bundles of data, helps you achieve robustness.

Part 6 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/object6.html
Artima.com is created by Bill Venners