Agile Javaв„ў: Crafting Code with Test-Driven Development

Java allows you to access fields of an object, just like you can call a method:

public void testCreate() { final String firstStudentName = "Jane Doe"; Student firstStudent = new Student(firstStudentName); assertEquals(firstStudentName, firstStudent.getName()); final String secondStudentName = "Joe Blow"; Student secondStudent = new Student(secondStudentName); assertEquals(secondStudentName, secondStudent.getName()); assertEquals(firstStudentName, firstStudent.name); }

If you run this test, it will pass. However, it demonstrates particularly poor object-oriented coding style.

Do not directly expose fields to other objects.

Suppose you want to design the Student class so that a student's name is immutableit cannot be changed once you've created a Student object. The following test code demonstrates how allowing other objects to access your attributes can be a bad idea:

final String firstStudentName = "Jane Doe"; Student firstStudent = new Student(firstStudentName); firstStudent.name = "June Crow"; assertEquals(firstStudentName, firstStudent.getName());

The test shows that Student client codecode that is interacting with the Student objectcan directly modify the String stored in the name instance variable. While this doesn't seem like a terrible affront, it eliminates any control you have over clients changing your object's data. If you want to allow client code to change the Student's name, you can create a method for the client to use. For example, you could create a method called setName that takes a new name String as parameter. Within the setName method, you could include code for any additional control you needed.

Make the above change to StudentTest and demonstrate for yourself that the test fails.

To protect your fieldsto hide themyou should designate them as private. Change the Student class to hide the name field.

class Student { private String name; ...

After doing so, other code that attempts to access the field will not even compile. Since the code in Student test refers to the name field directly:

assertEquals(firstStudentName, firstStudent.name);

you will receive a compilation error:

name has private access in Student assertEquals(firstStudentName, firstStudent.name); ^ 1 error

Remove the offending line, recompile, and retest.

The other interest in making fields private is to reinforce the notion of object orientation and encapsulation: An object-oriented system is about behavior, not data. You want to accomplish things by sending messages. You also want to encapsulate implementation details. Perhaps later you want to change the Student class to store both first and last names and change the getName method to return the combined name parts. In that case, code that directly accesses the name field would no longer be valid.

As with any rule, there are exceptions. There are at least a couple legitimate reasons to not designate a field as private. (You'll learn about these much later.)

Категории