Виртуозное применение дженериков


Исходный код

private Map<Class<?>, Map<String, String[]>> compressDependencies(
      Map<Class<?>, Map<String, List<String>>> dependencies) {

    final Map<Class<?>, Map<String, String[]>> result =
        newFastMap<Class<?>, Map<String, String[]>>(dependencies.size());

    final Set<Entry<Class<?>, Map<String, List<String>>>> entrySet = dependencies.entrySet();

    for (Entry<Class<?>, Map<String, List<String>>> entry : entrySet) {
      final Map<String, List<String>> value = entry.getValue();
      final Map<String, String[]> desc = newFastMap<String, String[]>(value.size());
      final Set<Entry<String, List<String>>> subEntries = value.entrySet();

      for (Entry<String, List<String>> valueEntry : subEntries) {
        final List<String> list = valueEntry.getValue();
        if (list != null && !list.isEmpty()) {
          desc.put(valueEntry.getKey(), list.toArray(newString[list.size()]));
        }
      }
      result.put(entry.getKey(), desc);
    }
    return result;
  }

Что не так в этом коде

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

Вижу обилие сложных структур данных, которые явно соответствуют неким сущностям предметной области, но эти сущности не обозначены в коде как самостоятельные сущности в виде классов. В этом коде сущности создаются налету с помощью дженерика и существуют только на время выполнения операций, потом снова создаются налету и сразу исчезают. Их свойства и поведение не задокументированы явно в виде класса с полями и методами, они раскиданы мелкими порциями по разным алгоритмам; сущности разбиты на кусочки. Эти кусочки приходится собирать в голове, что создаёт значительную и ненужную нагрузку на мышление разработчика.

У свойств и операций нет собственных названий, приходится пользоваться обобщёнными getValueentrySetgetKey. Известно, что делают эти методы со своей структурой даных, но что происходит с точки зрения предметной области?

Второй момент заключается в том, что здесь, скорее всего, имеет место обращение к объектам разных уровней. Сначала мы работаем со списком зависимостей dependencies как с сущностью, потом погружается внутрь каждой зависимости, что уже неправильно. Вся работа с «внутренностями» отдельной зависимости должна инкапсулироваться в методы сущности «зависимость».

Теория

  • Проклятие стандартных библиотек
  • Принцип единственного уровня