Как я могу запретить нескольким экземплярам объекта иметь одинаковые атрибуты в Java

#java #oop

#java #ооп

Вопрос:

Ниже приведен мой фрагмент кода

 Account acc1 = new Account ("123", "James", "Savings");
Account acc2 = new Account ("234", "James", "Checking");
acc1.setNickName("James Account");
acc2.setNickName("James Account");


//Nick Name Method
private String nickName;

public void setNickName (String name)
{
    nickname = name;

}
  

Мой вопрос в том, как я могу запретить acc2 объекту иметь значение NickName, такое же, как у acc1 ?

Я хочу убедиться, что в setNickName методе существует механизм, предотвращающий совпадение двух экземпляров объекта.

Комментарии:

1. Вы можете переопределить equals и hashCode

2. Не уверен, но переопределите hashCode() и equals() метод в Account классе.

3. Не могли бы вы подробнее остановиться на этом предложении, пожалуйста?

4. @C.Peck: Серьезно?? Это установщик . Вам не нужно видеть setNickName(String nickName) , не так ли?

5. Механизм предотвращения дублирования псевдонимов не должен быть в классе Account. Это должно быть в любой вещи, которая содержит коллекцию учетных записей.

Ответ №1:

Вы можете создать статический Set объект в своем Account классе и каждый раз, когда nickname добавляется, вы проверяете, существует ли он уже. Если это не так, то установите значение. Если он не существует, то у вас может быть своя собственная логика (я выбросил IllegalArgumentException )

 class Account {

private static Set<String> nickNameSet = new HashSet<>();

public void setNickName(String nickName) {
    if(nickNameSet.add(nickName))
    {
    this.nickName = nickName;
    }
    else {
        throw new IllegalArgumentException("Nick Name already exists");
    }
  }
}
  

Как указано @Makoto, определение Set объекта в Account классе приведет к тому, что все объекты account будут иметь доступ к нику других учетных записей. Если вас беспокоит скрытие данных, нам следует создать, скажем, новый класс AccountManager и делегировать ему логику идентификации дубликатов nickName .

Комментарии:

1. Я думал об этом, но проблема здесь заключается в сокрытии информации. Теперь каждая учетная запись знает псевдонимы всех других учетных записей. Это полезно в крайнем случае, но нарушает множество уровней разделения. Предположим, что затем нам нужно было проверить наличие уникальных идентификаторов; как мы могли бы выполнить это с помощью этого? (И я знаю, что здесь это не ограничение, но это пища для размышлений.)

2. Изменение поля на private не делает эти объекты менее осведомленными, поскольку каждый Account экземпляр имеет прямой доступ к этому полю.

3. @Makoto понял вашу точку зрения. Я определил Set в том же Account классе. Что вы сделали, так это определили новый AccountManager класс и определили это Set(Collection) там, а также делегировали логику для присвоения псевдонима там. Простая вещь, но имеет большое значение в отношении сокрытия данных. Спасибо, что указали на это

Ответ №2:

Это не так просто, как просто переопределить equals or hashCode в вашем Account объекте. Указывая ограничение на два разных экземпляра Account , это подразумевает, что оба экземпляра осведомлены друг о друге. В этом контексте их не будет; это два независимых экземпляра, которые на самом деле не должны знать друг о друге в реальности.

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

В этом контексте вам на самом деле не нужно переопределять ни equals , ни hashCode поскольку это в любом случае не даст вам того, что вы хотите; у вас не всегда будут две идентичные учетные записи с одинаковым ником, и искажение equals метода для уделения внимания одному полю кажется неправильным.

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

Механизм прост:

  • Если у нас есть учетная запись с ником, мы не обновляем ее. Если мы этого не сделаем, мы обновим его по идентификатору.
  • Теперь эта служба отвечает за создание всех учетных записей и управление ими.

 public class AccountManager {

    final List<Account> accounts = new ArrayList<>();

    public Account createAccount(String id, String name, String type) {
        Account account = new Account(id, name, type);
        accounts.add(account);
        return account;
    }

    public boolean setNickName(String id, String nickName) {
        Optional<Account> existingAccount = accounts.stream()
                                    .firstMatch(a -> a.getNickName().equals(nickName));
        if(existingAccount.isPresent()) {
            return false; // don't allow modification to an account who has the same nickname
        } else {
            accounts.stream()
                    .firstMatch(a -> a.getId().equals(id))
                    .ifPresent(a -> a.setNickName(nickName));
            return true;
        }
    }
}
  

Теперь, с этим классом, вы должны получить то, что хотите — любая учетная запись, управляемая AccountManager , не сможет иметь одинаковый псевдоним.