简体   繁体   中英

It''s never a good idea for a public class to expose fields directly, but why it is less harmful if the fields are immutable?

I'm reading an article from Effective Java Item 14 - In public classes, use accessor methods, not public fields. In the book it says: While it's never a good idea for a public class to expose fields directly, it is less harmful if the fields are immutable.

My question is why it's less harmful if the fields are immutable? Could you give a real-life example to justify? Here is the code example in the book.

/ Encapsulation of data by accessor methods and mutators
class Point {
   private double x;
   private double y;

   public Point(double x, double y) {
      this.x = x;
      this.y = y;
   }

   public double getX() { return x; }
   public void setX(double x) { this.x = x; }

   public double getY() { return y; }
   public void setY(double y) { this.y = y; }
}

While it's never a good idea for a public class to expose fields directly, it is less harmful if the fields are immutable.

// Public class with exposed immutable fields - questionable
public final class Time {
   public final int hour;
   public final int minute;

   public Time(int hour, int minute) {
      this.hour = hour;
      this.minute = minute;
   }
}

If your object has solely immutable fields, most likely that object itself can be regarded immutable.

Which means: upon creation, that object will never change its content. Thus you can reference to that object from any number of places. And no other object needs to worry that the corresponding data will magically change, because some other code did something.

Essentially, the difference between direct field access and providing a setter method isn't what matters: The only thing that makes a huge conceptual difference. mutable vs immutable.

And note: ideally, the public methods of a class provide you behavior that client code can use!

It's explained clearly in the following sentence and then he gives an example. I have the second edition, maybe you have the first edition and it's missing from it?

While it's never a good idea for a public class to expose fields directly, it is less harmful if the fields are immutable. You can't change the representation of such a class without changing its API, and you can't take auxiliary actions when a field is read, but you can enforce invariants . (emphasis mine)

The enforcing invariants example given in the book:

For example, this class guarantees that each instance represents a valid time:

// Public class with exposed immutable fields - questionable
public final class Time {
    private static final int HOURS_PER_DAY = 24;
    private static final int MINUTES_PER_HOUR = 60;

    public final int hour;
    public final int minute;

    public Time(int hour, int minute) {
        if (hour < 0 || hour >= HOURS_PER_DAY)
            throw new IllegalArgumentException("Hour: " + hour);
        if (minute < 0 || minute >= MINUTES_PER_HOUR)
            throw new IllegalArgumentException("Min: " + minute);
        this.hour = hour;
        this.minute = minute;
    }
// Remainder omitted
}
// Public class with exposed immutable fields - questionable
public final class Time {
   public final int hour;
   public final int minute;

   public Time(int hour, int minute) {
      this.hour = hour;
      this.minute = minute;
   }
}

With the above code, the Class which is creating the object of the above class must have knowledge about the fields. This introduces a tight coupling.

Also, if you are coding to interfaces when the object is declared using the interface name all the implementations will implement the methods and it will be easier for the developer to access the value using methods and every implementation can use these class level variables and return as per the implementation details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM