Есть ли оправдание для "псевдотипного антипаттера"?

У меня относительно сложный общий тип (скажем Map<Long,Map<Integer,String>>), который я использую внутри класса. (Внешняя видимость отсутствует, это просто деталь реализации.) Я хотел бы скрыть это в typedef, но Java не имеет такого средства.

Вчера я снова открыл следующую идиому и был разочарован, узнав, что считается анти-шаблоном.


class MyClass
{
  /* "Pseudo typedef" */
  private static class FooBarMap extends HashMap<Long,Map<Integer,String>> { };

  FooBarMap[] maps;

  public FooBarMap getMapForType(int type)
  {
    // Actual code might be more complicated than this
    return maps[type];
  }

  public String getDescription(int type, long fooId, int barId)
  {
    FooBarMap map = getMapForType(type);
    return map.get(fooId).get(barId);
  }

  /* rest of code */

}

Может ли быть какое-либо оправдание для этого, когда тип скрыт и не является частью библиотечного API (который при моем чтении является основным возражением Goetz на его использование)?

Ответ 1

Реальная проблема заключается в том, что эта идиома создает высокую связь между вашим псевдопечати и вашим клиентским кодом. Однако , поскольку вы используете FooBarMap в частном порядке, нет реальных проблем связи (это детали реализации).

NB

Современная Java IDE должна окончательно помочь справиться со сложными родовыми типами.

Ответ 2

ИМО, проблема с анти-паттернами Java в том, что они поощряют черно-белое мышление.

В действительности большинство анти-паттернов нюансов. Например, связанная статья объясняет, как псевдо-typedefs приводит к API, чьи сигнатуры типов слишком ограничительны, слишком привязаны к конкретным решениям реализации, вирусным и так далее. Но это все в контексте публичных API. Если вы храните псевдопечатания вне общедоступных API-интерфейсов (т.е. ограничивает их классом или, возможно, модулем), они, вероятно, не причинят реального вреда и могут сделать ваш код более читабельным.

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

Ответ 3

Для публичных интерфейсов мне не нравятся общие типы, потому что они не имеют никакого значения. Мне вид метода с аргументом HashMap < Long, Map < Integer, String → очень похож на те C-методы, как foo (int, int, int, void *, int) и т.д. Наличие реального типа просто делает код намного легче читать. Для публичного интерфейса было бы лучше создать FooBarMap, который обертывает HashMap < Long, Map < Integer, String → , а не "typedef", но для внутреннего использования класса я вообще не вижу нисходящей стороны.

Ответ 4

Без этого псевдо-typedef я бы предпочел написать

private Map<Long,Map<Integer,String>>[] maps;

и если я когда-нибудь решит изменить класс реализации от HashMap до TreeMap или Java7GreatEnhancedWonderfulMap:-) ничего не сломается. Но с этим вы застряли в HashMap. Ну, вы можете сделать:

interface FooBarMap extends Map<Long,Map<Integer,String>> { };
class FooBarHashMap extends HashMap<Long,Map<Integer,String>> implements FooBarMap{ };

но он становится все более громоздким.

Ответ 5

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

Но я не вижу веских оснований для того, чтобы не использовать его локально, при условии, что это упростит вам жизнь и код станет более читаемым - и вы знаете, что делаете. Брайан может обобщить и посоветовать против него в любой ситуации, но что его чувство Goetz: p

Ответ 6

Если вы используете его только в небольшом локализованном модуле кода, проблемы небольшие, правда.

Thing is, так же как и выигрыш: ваша программа, вероятно, даже не будет иметь текстовое значение меньше, пока вы не будете ссылаться на псевдо-typedef 5+ раз, что означает, что область, в которой она видна, должна быть нетривиальной.

Вероятно, я бы не переписал код, который сделал это, но, похоже, это была плохая привычка.