Возвращение неизменного списка - PullRequest
4 голосов
/ 21 февраля 2012

Я создаю класс с именем Question.У этого класса есть ответы, поэтому я хочу иметь возможность вернуть список ответов, прикрепленных к нему.

Однако, если пользователь вносит изменения в ответ, я хочу, чтобы пользователь вызвал метод обновления, чтобы я мог выполнить дополнительные проверки и т. Д. Сейчас, если пользователь получает список ответов, он все еще может изменитьответьте, сказав question.getAnswers().get(0).setDescription("BLAH BLAH").

Так что я подумал о том, чтобы вернуть копию каждого ответа, и позволить пользователю изменить это, и он должен объединить / обновить его обратно к вопросу.При таком подходе я могу гарантировать, что ответ верен, но метод ответа равно основывается на поле description и correct, а не на поле id, потому что я использую JPA.Если пользователь изменяет ответ с помощью этого подхода, метод обновления не найдет ответ, потому что поле описания изменилось, и оно больше не равно, поэтому оно не находит его в списке.

Любые советы?

public void updateAnswer(Answer answer) {
    int index = answers.indexOf(answer);
    answers.set(index, answer);
}

public List<Answer> getAnswers() {
    return Collections.unmodifiableList(answers);
}


@Test
public void shouldUpdateAnswerInQuestion() {
    // Get first answer, make an update on the description
    // and then update answer on question.
    Answer answerThatWillBeUpdated = question.getAnswers().get(0);
    String updatedAnswerDescription = "Hey, it is now updated!";
    answerThatWillBeUpdated.setDescription(updatedAnswerDescription);
    question.updateAnswer(answerThatWillBeUpdated);

    // After updating check that the answer in the list is equal
    // to the answer updated.
    Answer answerFromList = question.getAnswers().get(0);

    assertEquals(answerThatWillBeUpdated, answerFromList);
}

Класс ответа:

public class Answer {

    private long id;
    private String description;
    private Boolean correct;
    ...
}

Ответы [ 4 ]

1 голос
/ 21 февраля 2012

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

Простой и прямой ответ: программа для интерфейса, а не для реализации.Если вы хотите принудительно вызывать метод обновления после изменения метода установки, рассмотрите возможность использования шаблона Decorator.

  • создать интерфейс
  • сделать так, чтобы ваш конкретный класс реализовал этот интерфейс (Ответ)
  • добавить конкретный класс (выберите лучшее имя, но AnswerDecorator), который реализует интерфейскоторый принимает конкретный класс в конструкторе класса, упомянутого в пункте выше

Затем вы просто делегируете все методы внутреннему экземпляру, а для методов, которые вы хотите вызвать update, выполните что-то вроде этого:

public void setField (int a) {innerInstance.setField (a);Обновить(...);}

0 голосов
/ 21 февраля 2012

У кода клиента есть список, поэтому он знает индекс списка, и он скажет вам, какой из них обновить:

public void updateAnswer(int index, Answer newAnswer) {
    answers.set(index, answer);
}

// ...

Answer answerThatWillBeUpdated = question.getAnswers().get(0);
String updatedAnswerDescription = "Hey, it is now updated!";
answerThatWillBeUpdated.setDescription(updatedAnswerDescription);
question.updateAnswer(0,answerThatWillBeUpdated);
0 голосов
/ 21 февраля 2012

Как правило, я знаю 2 решения.

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

  2. Другое решение - вернуть список немодифицируемых объектов, то есть объектов, которые выдают исключение, когда пользователь пытается вызвать свои установщики.

Существует несколько возможных реализаций этого решения.

2.1.Модифицируйте сеттеры ваших модельных классов.Все сеттеры должны иметь возможность генерировать исключение, если объект создается в режиме только для чтения.

2.2.Пользовательская оболочка (декоратор) выкройки.

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

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

2.3.Используйте аспекты.Например AspectJ.

0 голосов
/ 21 февраля 2012

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

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