сделать класс неизменным в Java - PullRequest
7 голосов
/ 19 марта 2012

Чтобы сделать класс неизменным, я могу сделать следующее:

1) Сделать класс окончательным
2) не предоставлять сеттеры
3) пометить все переменные как окончательные

Но если у моего класса есть другой объект какого-то другого класса, то somone может изменить значение этого объекта

class MyClass{
 final int a;
 final OtherClass other 

 MyClass(int a ,OtherClass other){
  this.a = a;
  this.other = other;
 }

 int getA(){
   return a;
 }

 OtherClass getOther(){
   return other;
 }

 public static void main(String ags[]){
  MyClass m = new Myclass(1,new OtherClass);
  Other o = m.getOther();
  o.setSomething(xyz) ; //This is the problem ,How to prevent this?

}
}

Ответы [ 8 ]

3 голосов
/ 19 марта 2012

A) Сделайте также OtherClass неизменным

или

B) Не разрешайте прямой доступ к объекту OtherClass, вместо этого предоставляя только геттеры для работы в качестве прокси.

Изменить, чтобы добавить: Вы могли бы сделать глубокую копию OtherClass и вернуть копию, а не оригинал, но обычно это не тот тип поведения, который вы бы сделали ожидать в Java.

2 голосов
/ 19 марта 2012

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

  1. У внешнего пользователя нет возможности изменить значение объекта
  2. Гарантия того, что пользователь в любое время читает или делаетиспользование значения объекта в будущем приведет к тому же результату

Важное примечание : на самом деле нормально иметь изменяемые данные внутри неизменяемого объекта , так какпока он ведет себя как неизменный объект с точки зрения пользователя API .Рассмотрим, например, java.lang.String: хотя он обычно считается окончательным неизменяемым классом, на самом деле он имеет изменяемое внутреннее поле для кэширования hashCode (не многие знают это!).

ответьте на свой вопрос: если вы хотите, чтобы в неизменяемом объекте содержался другой (изменяемый) объект, вам обычно нужно выполнить одно или несколько из следующих действий:

  • Гарантия того, что никто другой не сможет изменить значение изменяемого объекта.Обычно это означает, что никто другой не может иметь ссылку на изменяемый объект, поэтому обычно это возможно только в том случае, если вы создаете объект самостоятельно, а не принимаете ссылку извне.
  • Примите оборонительные мерыглубокая копия изменяемого объекта, и не раздавать ссылки на новую копию.Разрешить только те операции, которые читают новую копию в общедоступном API.Если вам нужно раздать ссылку на этот объект, вам нужно взять еще одну защитную копию (чтобы не раздавать ссылку на внутреннюю копию).
  • Использовать неизменную оболочку дляизменчивый объект.Что-то вроде Collections.unmodifiableList .Это полезно, если вы хотите разослать ссылку на внутренний изменяемый объект, но не хотите подвергаться риску его изменения.

Все эти решения немного хакерские - лучшеОбщее решение заключается в том, чтобы избежать использования изменяемых объектов в неизменяемых объектах.В долгосрочной перспективе это вызывает проблемы, потому что рано или поздно изменчивая ссылка будет просочиться, и вам будет чрезвычайно трудно найти ошибку.Вам лучше перейти к полной иерархии неизменных объектов (подход, принятый такими языками, как Scala и Clojure)

1 голос
/ 16 декабря 2014

Создать неизменный класс в Java можно следующими способами:

1.Не указывайте методы установки.

2. Сделайте все поля как окончательные и приватные.

3. Сделать класс окончательным.

1 голос
/ 19 марта 2012

Но если у моего класса есть другой объект другого класса, то somone может изменить значение этого объекта ...

Объекты Java не являются примитивными.Если вы пометите примитив как окончательный, то его значение не может быть изменено после назначения.Однако содержимое объекта не может быть окончательным, только ссылки на объекты могут быть окончательными.Таким образом, вы не можете создать объект таким способом.

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

1 голос
/ 19 марта 2012

Вы не можете (разумно) остановить это в Java.если у вас нет контроля над другим классом, есть способы эффективно получить неизменное поведение, но на практике это может быть очень дорого.по сути, вы всегда должны возвращать копию этого класса в любом открытом методе, возвращающем значения.(JDK на самом деле имеет эту проблему с классом TimeZone).

1 голос
/ 19 марта 2012

Все объекты, на которые есть ссылки в неизменяемом классе, должны быть неизменяемыми или, по крайней мере, быть инкапсулированными как закрытые и гарантировать, что они не будут изменены (не внутри методов вашего класса и определенно не извне). Например, если у вас есть такая ситуация:

public class MyImmutable {
    private MutableClass mutableObject;
}

... Вы не можете предоставить метод getMutableObject(), потому что это откроет дверь для внешних модификаций, например:

myImmutable.getMutableObject().setSomeAttribute(newValue);

В особом случае, описанном выше, все коллекции и / или карты должны быть неизменными с использованием методов ummodifiableXXX() в классе Collections.

1 голос
/ 19 марта 2012

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

1 голос
/ 19 марта 2012

Я предполагаю, что OtherClass (кстати, один раз вы говорите "Другое") - это класс, которым вы не управляете или у которого должен быть установщик.

Если вы не можете удалить getOtherизмените его на getOtherView и верните доступное только для чтения представление other.Будут обёртки для всех методов get, но не заданных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...