Есть ли когда-нибудь оправдание для «антипаттерна псевдотипа»? - PullRequest
9 голосов
/ 07 августа 2009

У меня есть относительно сложный универсальный тип (скажем, 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 (что, на мой взгляд, является основным возражением Гетца против его использования)?

Ответы [ 6 ]

10 голосов
/ 07 августа 2009

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

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

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

5 голосов
/ 07 августа 2009

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

NB

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

2 голосов
/ 07 августа 2009

Для общедоступных интерфейсов я не люблю видеть универсальные типы, потому что они не имеют значения. Для меня видение метода с аргументом HashMap > очень похоже на те методы C, как foo (int, int, int, void *, int) и так далее. Наличие реального типа делает код намного проще для чтения. Для общедоступного интерфейса было бы лучше создать FooBarMap, который обернет HashMap >, а не 'typedef', но для внутреннего использования класса я не вижу никакой обратной стороны.

0 голосов
/ 07 августа 2009

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

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

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

0 голосов
/ 07 августа 2009

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

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

0 голосов
/ 07 августа 2009

Без этого псевдотипа я бы лучше написал

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{ };

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...