10

我有一个相对复杂的泛型类型(比如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 对使用它的主要反对意见),这是否有任何理由?

4

6 回答 6

13

IMO,Java 反模式的问题在于它们鼓励非黑即白的思维方式。

实际上,大多数反模式都是有细微差别的。例如,链接的文章解释了伪类型定义如何导致 API 的类型签名过于严格,过于依赖特定的实现决策、病毒等。但这都是在公共 API 的上下文中。如果您将伪类型定义排除在公共 API 之外(即,将它们限制为一个类,或者可能是一个模块),它们可能不会造成真正的伤害,并且它们可能会使您的代码更具可读性。

我的观点是,您需要了解反模式,并对何时何地避免它们做出合理的判断。简单地采取“我永远不会做 X,因为它是一种反模式”的立场意味着有时你会排除实用上可接受的,甚至是好的解决方案。

于 2009-08-07T14:15:25.240 回答
5

真正的问题是这个习惯用法在您的伪 typedef和您的客户端代码之间产生了高度耦合。但是,由于您是FooBarMap私下使用,因此没有真正的耦合问题(它们是实现细节)。

注意

现代 Java IDE 肯定有助于处理复杂的泛型类型。

于 2009-08-07T07:56:24.493 回答
3

对于公共接口,我不喜欢看到泛型类型,因为它们没有意义。对我来说,看到带有 HashMap<Long,Map<Integer,String>> 参数的方法很像 foo(int, int, int, void*, int) 等 C 方法。拥有一个真实的类型只会让代码更容易阅读。对于公共接口,最好创建包装 HashMap<Long,Map<Integer,String>> 而不是“typedef”的 FooBarMap,但对于类内部使用,我根本看不到任何不利方面。

于 2009-08-07T08:03:05.460 回答
0

如果没有这个伪类型定义,我宁愿写

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

但它变得越来越麻烦。

于 2009-08-07T08:10:18.333 回答
0

在将其放入公共界面时,他对此有很好的看法。这个成语是在模仿某种形式的语法糖,它不应该影响您向客户展示的内容。

但是我认为没有充分的理由不在本地使用它,只要它让您的生活更轻松并且代码更具可读性 - 并且您知道自己在做什么。在任何情况下,Brian 都可以概括并强烈反对它,但那是他的 Goetz 感觉:p

于 2009-08-07T08:10:33.200 回答
0

如果您只在一个小的本地化代码单元中使用它,那么问题很小,确实如此。

事实是,收益也是如此:在您引用伪 typedef 5 次以上之前,您的程序可能甚至不会在文本上变得更小,这意味着它可见的区域必须是不平凡的。

我可能不会重写这样做的代码,但这似乎是一个坏习惯。

于 2009-08-07T08:16:43.623 回答