#java #constructor #default-constructor
#java #конструктор #default-конструктор
Вопрос:
У меня было много тестовых наборов, запущенных в классе MyClass, с использованием его конструктора по умолчанию: MyClass().
Теперь требования MyClass изменились, и пользователь может предоставить хэш-карту для указания некоторых пар. Теперь MyClass должен иметь хотя бы одну пару и выдает исключения, если одно из них равно null.
Я надеялся создать другой конструктор по умолчанию, чтобы избежать необходимости переписывать все методы тестирования, что-то вроде:
public MyClass() {
HashMap<KeyClass, ValueClass> hashMap = HashMap<KeyClass, ValueClass>();
hashMap.put(KeyClass.someValue, new ValueClass());
this(hashMap);
}
Теперь это не работает, потому что сначала я должен вызвать другой конструктор, поэтому я подумал о написании какого-нибудь метода
private static HashMap<KeyClass, ValueClass> getDefaultHashmap();
и используйте его для вызова другого конструктора следующим образом:
public MyClass() {
this(MyClass.getDefaultHashmap());
}
Но мне это показалось не очень хорошим стилем, поэтому я надеялся, что вы могли бы сказать мне, как правильно сделать что-то подобное!
Комментарии:
1. Если вы пытаетесь добавить тестовые данные в свой тестируемый класс (я имею в виду создать хэш-карту по умолчанию в MyClass, чтобы протестировать ее) Я думаю, что это плохая идея. Лучше всего использовать конструктор с HashMap anbd, чтобы предоставить его из ваших тестов.
2. На самом деле я запускаю тесты на других методах, которые присутствовали до изменения, поэтому они полностью независимы от хэш-карты
3. Верно, но вам действительно нужно иметь хэш-карту по умолчанию в MyClass или это просто потому, что вы столкнулись с проблемой при тестировании?
4. Нет, мне действительно не нужен конструктор по умолчанию, это действительно вопрос удобства, мне, конечно, также было интересно, как я мог бы справиться с этим, если для этого было бы на 100% необходимо иметь конструктор по умолчанию. И последнее, но не менее важное, возможно, мне придется изменить больше материала позже, чтобы не пришлось слишком часто открывать старые тестовые наборы, я планировал всегда предоставлять конструктор по умолчанию, чтобы также быть уверенным, что никакие исключения не генерируются внезапно или около того 🙂
5. Я согласен с reef — если предполагаемый шаблон использования для вашего класса не требует конструктора по умолчанию, то я бы выступил против добавления одного только для экономии работы в ваших модульных тестах. Предположительно, ничто не помешало бы пользователю вашего класса вызвать этот конструктор по умолчанию, который, вероятно, привел бы к поведению, которого вы не ожидаете?
Ответ №1:
Вы могли бы встроить создание хэш-карты:
public MyClass() {
this(new HashMap<KeyClass, ValueClass>() {{
put(KeyClass.someValue, new ValueClass());
}});
}
Но вам пришлось бы игнорировать предупреждение serial-id, чтобы сохранить его «красивым».
Комментарии:
1. Спасибо потрясающе! Я приму ваш ответ, как только истечет срок 🙂
2. Добро пожаловать — и @Peter: обычно я все еще печатаю, когда вижу, что появляется сообщение «опубликовано 4 новых ответа»! 😉
Ответ №2:
Лично я бы предпочел создать new HashMap(...)
в обоих конструкторах, а не пытаться обернуть создание в новый статический метод.
Ответ №3:
Вот решение, которое я обычно использую:
public MyClass {
private static Map<KeyClass, ValueClass> newMap() {
Map<KeyClass, ValueClass> result = new HashMap<KeyClass, ValueClass>();
result.put(KeyClass.someValue, new ValueClass());
return resu<
}
public MyClass() {
this(newMap());
}
public MyClass(Map<KeyClass, ValueClass> m) { ... }
}
Я предпочитаю это, чем подклассирование HashMap
-класса (как предложено @alpian) — кажется более чистым, а также не создает риска нарушения контракта метода equals() (описанного здесь: http://c2.com/cgi/wiki ?Двойная трассировка инициализации)
Комментарии:
1. Как это нарушает контракт метода equals()?
2. Это не происходит с HashMap, но с другими классами (чей метод equals() проверяет тип другого операнда путем вызова .getClass()), такие проблемы могут возникнуть.
Ответ №4:
Если вы хотите избежать создания нового анонимного подкласса HashMap, и вам нужна только одна пара, и вы не хотите создавать новый статический метод, вы могли бы сделать это:
public MyClass() {
this(new HashMap<KeyClass, ValueClass>(
Collections.singletonMap(KeyClass.someValue, new ValueClass())));
}
Если ваш другой конструктор берет карту и копирует ее, вам может даже не понадобиться создавать хэш-карту
public MyClass() {
this(Collections.singletonMap(KeyClass.someValue, new ValueClass()));
}
Комментарии:
1. Спасибо, это действительно, вероятно, более чистый способ, единственное, что методом alpian я могу добавить больше элементов, так что это пригодится. Хотя я согласен, это, вероятно, самое элегантное решение только для одного элемента.