Неизменяемый интерфейс

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

В объектно-ориентированном программировании, «неизменяемый Интерфейс» — это шаблон для проектирования неизменяемого объекта.[1][2][3] Неизменяемый интерфейс включает в себя определение типа, который не предоставляет никаких методов, которые могут изменить состояние. Объекты, на которые ссылается этот тип, выглядят как неизменяемые.

Пример[править | править код]

Java[править | править код]

Рассмотрим класс java, который представляет собой двухмерную точку.

public class Point2D {
    private int x;
    private int y;
    public Point2D(int x, int y) { this.x = x; this.y = y; }

    public int getX() { return this.x; }
    public int getY() { return this.y; }

    public void setX(int newX) { this.x = newX; }
    public void setY(int newY) { this.y = newY; }
}

Класс Point2D является изменяемым: его состояние может быть изменено после создания, если вызвать один из методов-сеттеров (setX() или setY()).

Неизменяемый интерфейс для Point2D может быть определен как:

public interface ImmutablePoint2D {
    public int getX();
    public int getY();
}

Сделав Point2D реализующим ImmutablePoint2D, код клиента теперь может использовать тип, который не имеет изменяющих методов, и, таким образом, остается неизменяемым. Это демонстрируется в следующем примере:

ImmutablePoint2D point = new Point2D(0,0); // на конкретный экземпляр Point2D ссылается неизменяемый интерфейс
int х = point.getX(); // допустимый вызов метода
point.setX(42); // ошибка компиляции: метод setX() не существует в типе ImmutablePoint2D

Имея только неизменяемый интерфейс, невозможно вызвать метод, который изменяет состояние конкретного объекта.

Преимущества[править | править код]

  • Четко передает намерения о неизменяемости типа.
  • В отличие от типов, реализующих шаблон неизменяемая обертка, не нужно нейтрализовать изменяющие методы, путем использования инструкции «нет эксплуатации», или бросать исключение во время выполнения, когда изменяющий метод вызывается.

Недостатки[править | править код]

  • Возможно для экземпляров, на которые ссылается неизменяемый интерфейс, привести тип к конкретному изменяемому типу, и уже тогда изменить состояние. Например:
public void mutate(ImmutablePoint2D point) {
    ((Point2D)point).setX(42); // допустимый вызов, поскольку
                               // аргумент point был приведен к типу Point2D
}
  • Конкретные классы должны явно объявлять в их реализации неизменяемый интерфейс. Это не может быть возможно, если конкретный класс «принадлежит» стороннему коду, например, если оно содержится в библиотеке.
  • Объект не является на самом деле неизменяемым и, следовательно, не подходит для использования в структурах данных, требующих неизменяемость, таких как хэш-map-ы. И объект может быть изменен одновременно на «изменяемой стороне».
  • Некоторые оптимизации компилятора, доступные для неизменяемых объектов, могут быть недоступны для изменяемых объектов.

Альтернативы[править | править код]

Альтернативой неизменяемому интерфейсу является шаблон неизменяемая обёртка.

Ссылки[править | править код]