Java, делая класс неизменным - PullRequest
0 голосов
/ 09 мая 2018

Я наткнулся на это упражнение онлайн, где у меня есть два класса, и я должен сделать класс Tutor неизменным. Тем не менее, единственное, о чем я могу подумать, это добавить final в поле name. Когда дело доходит до конструктора, я не думаю, что мне нужно менять инициализацию переменной name, так как String неизменен. Я не уверен, как подходить к коллекции и как сделать эту часть конструктора неизменной. В соответствии с заданием я не должен менять класс ученика (который, как я вижу, изменчив)

public class Student {

private String name;
private String course;


public Student(String name, String course){

this.name = name;
this.course = course;

}

public String getName(){ 
return name; 
}

public String getCourse(){ 
return course; 
}

public void setName(String name) {
this.name = name;
}

public void setCourse(String course){
this.course = course;
}

}




public final class Tutor {
private String name;
private final Set<Student> tutees;

public Tutor(String name, Student[] students){
this.name = name;
tutees = new HashSet<Student>();
for (int i = 0; i<students.length; i++)
tutees.add(students[i]);
}


public Set<Student> getTutees(){
return Collections.unmodifiableSet(tutees);
}

public String getName(){ 
return name; 
}

}

Ответы [ 4 ]

0 голосов
/ 09 мая 2018

Класс Tutor представляет множество аспектов, способствующих его неизменности:

  • класс окончательный
  • Set<Student> защищен от изменений
  • нет метода, позволяющего напрямую изменять состояние класса

Однако защитная копия конструктора не завершена.
Также необходимо скопировать элементы Student s переданного массива. В противном случае клиент конструктора может изменить любой их экземпляр и сделать изменяемый экземпляр Tutor, например:

Student[] students = ...;
Tutor tutor = new Tutor(name, students);
students[0].setName("new Name!"); // break the immutability of Tutor

Вы должны написать что-то вроде:

public Tutor(String name, Student[] students){
  this.name = name;
  tutees = new HashSet<Student>();
  for (Student student : students){   
      Student copy = new Student(student.getName(), 
                                    student.getCourse());
      tutees.add(copy);
   }     
}

Кроме того, обратите внимание, что Set, возвращаемое getTutees(), не модифицируется, но элементы, содержащиеся в нем как Student, являются изменяемыми. Таким образом, чтобы сделать Tutor неизменным, вы также должны создать копию элементов Student при возврате getTutees(), например:

public Set<Student> getTutees(){
   Set<Student> students = new HashSet<>();
   for (Student student : tutees){
      Student copy = new Student(student.getName(), 
                                    student.getCourse());
      students.add(copy);
   }     
   return Collections.unmodifiableSet(students);
}

Как вы можете заметить, для получения неизменяемости в этих условиях (экземпляр, который мы хотим неизменным, но который содержит коллекцию, ссылающуюся на изменяемые экземпляры), требует написания большего количества кода (для чтения / обслуживания / тестирования) и выполнения большей обработки (так медленно, чтобы выполнить).
Если бы Student был неизменным классом, оригинального getTutees() и исходного конструктора было бы достаточно.

0 голосов
/ 09 мая 2018

Правильный способ сделать объект неизменным состоит в следующем:

  1. Объявить объект окончательным
  2. Не предоставлять методы установки
  3. Сделать все поля приватными
  4. Сделать изменяемые поля окончательными
  5. Использовать глубокое копирование в конструкторе
  6. Клонируйте объекты в методах получения, чтобы вы не возвращали реальную ссылку.
0 голосов
/ 09 мая 2018

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

interface IStudent {
    public String getName();
    public String getCourse(); 
}

class Student : implements IStudent { ...} 

и в вашем репетиторе вы возвращаете Set<IStudent>

0 голосов
/ 09 мая 2018

Чтобы сделать класс Tutor неизменным, вы должны использовать модификатор final для всех полей внутри Tutor, а не для определения класса Tutor.

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