#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
, не сможет иметь одинаковый псевдоним.