Java Programming   Java Programming
 |Sofia Home | Content Gallery |
Home
Syllabus
Schedule
Lessons
Assignments
Resources

Lesson 9.4 Methods

Accessor and Mutator Methods

While the LTextField class is coming along, it still has a ways to go. For instance, we still can't even do something as simple as this:

String addr = addrLTF.getText();

or this:

addrLTF.setLabel("Address:");

To accomplish both of these, you'll need to learn about accessor and mutator methods. Along the way, you'll be introduced to a new access control keyword, private.

Using Your Objects

If our LTextField objects are going to act like the built-in objects, then they should respond to messages. Of course, the LTextField class already responds to Component messages because we extended the Panel class when we created it. Anything we can tell a Panel to do, we can tell an LTextField object to do, and it will obey.

Unfortunately, the individual pieces of our LTextField are not so accommodating. We cannot get the text out of our TextField, for instance, making the whole class pretty useless for real work. To fix this, we need to add methods to our class.

Designing Methods

Although we know that our class needs some methods, how do we decide exactly what methods we should add? Well, just as we did when adding our constructors, we need to design our class by using it. 

Start by asking yourself, "What methods would I like to use?" Here's the minimal list that I came up with. 

I want to be able to:

  • Get the text from the TextField object
  • Set the text of the Label object
  • Clear the text from the TextField object
Back to Top

A "Possible" Solution

Here's one way of going about this that doesn't require any changes to the LTextField class at all:

Using Direct Access
LTextField ltf = new LTextField();
ltf.theLabel.setText(“New Label Text”);
String ans = ltf.theText.getText();
ltf.theText.setText("");

This meets all of our goals. I can change the text on the Label, I can retrieve the text from the TextField, and I can clear the TextField in anticipation of the next entry. 

So what’s wrong with this? Two things.

First, to use my objects, users must know the names and types of the fields. That means I cannot change the implementation of my class without affecting my users' code. By contrast, if the only access to my object's data is through a method--the object's interface--then I'm free to change the implementation at will.

Here's an example. Suppose that I create a class that initially stores a piece of information as a double, but that I later need to change the way the data is stored to a String

Image illustrates changing the implementation of a class with String data members.

If my users directly access the field, value, when I make my change, every piece of their code that uses my component will break. If, on the other hand, I provided a method in my classes public interface, like the getStringResult() shown here, my changes will be transparent to my users.

The second problem with direct user access is that I now have no control over how the contents of the fields are changed. If a set of operations must be performed in a particular order, I now have no way of enforcing that.

The OOP Commandments

These problems, although they might not seem insurmountable, lead to three "commandments" that are as sacrosanct as anything in object oriented programming. These rules are the OOP equivalent of structured programming's "eliminate the goto" rule.

These rules are the basis for the principle of encapsulation:

  • The insides of objects should not be visible from outside. After all, in the real world, that's why we're all covered with skin.
  • The only access to the inside of an object should be through its public methods. The public methods of an object make up its interface.
  • Do not ever directly access an object’s internal fields.
Of course, like the "no goto" rule, this one is sometimes honored in the breach, and for the same reason. Many so-called OOP libraries [Microsoft's C++ MFC classes for Windows programming being a prime example] throw encapsulation out the window when it gets in the way of performance or perceived performance.

As you'll see when we take a closer look at the AWT, Sun's Java programmers were not immune to this temptation.

Back to Top

Meet the private

To enforce the principle of encapsulation, Java uses the private keyword. When a field is declared private, only the methods in that class can access the field.

Here's how we'd add private access to the internal fields in the LTextField class:

private Label theLabel;
private TextField theText;

Once we've done this, direct access to these fields becomes impossible except for methods inside the LTextField class. To give users access to the fields we'll have to create some accessor and mutator methods. 

Let's take a look at what that means.

Back to Top

Accessors and Mutators

To give the user the ability to "read" a field you write an accessor method. Accessor methods are also sometimes called "getter" methods. 

The Java convention is to prefix such methods with the word "get." For the LTextField class we have only one value we want to retrieve from our component, the value of the text contained in the TextField. Let's call the method that returns that value getText().

Writing the method is quite easy, of course, because we can pass the actual work on to the TextField component. This forwarding of messages is called delegation, and is a common occurrence in object-oriented programs that use composition. 

Here is the LTextField getText() method:
The getText() Method
public String getText( ) 

  return theText.getText(); 
}

Mutations

When you need to change a value stored in a field, you write a mutator method. Mutators are so named because they change the state of an object--they cause it to mutate. Mutator methods are often called "setter" methods, and the Java convention is to use the prefix "set" before the method name.

In our class, we have two methods that need to change the state of our object. We want to be able to change the text displayed in the Label portion of our LTextField object, and we want to clear the text out of the TextField portion of our object.

Rather than calling the method that changes the Label setText(), which is what the actual call to the Label portion requires, we can name our method setLabel() to make it clear that we are changing the Label part of our object and not the TextField part.

Here's the code for setLabel(), which uses delegation just like the getText() method did:
The setLabel() Method
public void setLabel(String s)

  theLabel.setText(s); 
}

Mutator methods don't have to be named "set", especially when another name would make the purpose of the method clearer. Rather than using the name setText() for the mutator that clears the TextField, which would imply that the text could be set to anything, let's use the method name clearText(), which makes it perfectly clear what's going on. 

Here's the code for clearText():
The clearText() Method
public void clearText()
{
  theText.setText("");
}

Back to Top

Accessor/Mutator Advantages

You've already seen two reasons for avoiding direct access to your fields, but using the accessor/mutator scheme adds several advantages in addition to those already mentioned.

For instance, using accessor/mutators allows you:

  • To create read-only fields. You may want to let your users read the contents of a FileAllocationTable object, for instance, but not allow them to change its contents.
  • To create write-only fields, although these seem of less utility to me.
  • To validate the information that is stored in your fields before it's too late. By using mutators, for instance, you can make sure that each of your FractionalNumber objects are always "well formed", and that the denominator field never accidentally gets set to zero.
These are all important reasons, but the most important reason is to be able to change the implementation of a field without changing the interface. As you've already seen, separating the interface from the implementation allows you to change the insides of your objects, without changing the code that uses your objects.

Something to Talk About

What additional accessor or mutator method do you think is necessary for the LTextField class? Go ahead and write it, and tell us about it.

Please continue to the next section of this lesson.

 

Back to Top

 

Content Developed by Stephen Gilbert, Licensed under a Creative Commons License
Published by the Sofia Open Content Initiative
© 2004 Foothill-De Anza Community College District &The William and Flora Hewlett Foundation