Открытому классу не рекомендуется напрямую раскрывать поля, но почему это менее вредно, если поля неизменяемы?

Я читаю статью из Эффективного Java, пункт 14. В общедоступных классах используйте методы доступа, а не общедоступные поля. В книге говорится: «Хотя общедоступный класс никогда не будет хорошей идеей напрямую раскрывать поля, это менее вредно, если поля неизменяемы».

Мой вопрос: почему это менее вредно, если поля неизменяемы? Не могли бы вы привести пример из жизни в подтверждение? Вот пример кода в книге.

/ 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; }
}

Хотя публичному классу не рекомендуется напрямую раскрывать поля, это менее вредно, если поля неизменяемы.

// 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;
   }
}

person Saibō    schedule 25.10.2020    source источник
comment
Я думаю, что это больше связано с мнениями. По крайней мере, для меня, когда вы объявляете общедоступные поля, вы можете добавить тесную связь между компонентами, используя свой класс.   -  person Luiggi Mendoza    schedule 25.10.2020
comment
Я ценю быстрое принятие, и я рад, что мой ответ был полезен.   -  person GhostCat    schedule 26.10.2020


Ответы (3)


Если ваш объект имеет исключительно неизменяемые поля, скорее всего, сам объект можно считать неизменяемым.

Это означает: после создания этот объект никогда не изменит своего содержимого. Таким образом, вы можете ссылаться на этот объект из любого количества мест. И никакому другому объекту не нужно беспокоиться о том, что соответствующие данные волшебным образом изменятся, потому что какой-то другой код что-то сделал.

По сути, разница между прямым доступом к полю и предоставлением метода установки не имеет значения! Единственное, что имеет огромное концептуальное значение: изменяемый и неизменяемый.

И обратите внимание: в идеале общедоступные методы класса обеспечивают поведение, которое может использовать клиентский код!

person GhostCat    schedule 25.10.2020
comment
Ваш ответ очень полезен. Позвольте мне повторить: здесь важна неизменяемость, а не ограниченный доступ. :) - person Saibō; 26.10.2020

Это ясно объясняется в следующем предложении, а затем он приводит пример. У меня есть второе издание, может у вас есть первое издание и в нем его нет?

Хотя публичному классу не рекомендуется напрямую раскрывать поля, это менее вредно, если поля неизменяемы. Вы не можете изменить представление такого класса, не меняя его API, и вы не можете выполнять вспомогательные действия при чтении поля, но вы можете применять инварианты. (выделено мной)

Пример применения инвариантов, приведенный в книге:

Например, этот класс гарантирует, что каждый экземпляр представляет допустимое время:

// 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
}
person Oleg    schedule 25.10.2020
comment
Спасибо, что указали. Я просто понимаю, что то, что я читаю, является сжатой версией оригинальной книги. Это делает концепцию более ясной. :) - person Saibō; 26.10.2020

// 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;
   }
}

В приведенном выше коде класс, создающий объект вышеуказанного класса, должен иметь знания о полях. Это вводит жесткую связь.

Кроме того, если вы кодируете интерфейсы, когда объект объявлен с использованием имени интерфейса, все реализации будут реализовывать методы, и разработчику будет проще получить доступ к значению с помощью методов, и каждая реализация может использовать эти переменные уровня класса и возвращать как в деталях реализации.

person unnik    schedule 25.10.2020