Вызов другого конструктора с хэш-картой «по умолчанию»

#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 я могу добавить больше элементов, так что это пригодится. Хотя я согласен, это, вероятно, самое элегантное решение только для одного элемента.