我有一个相对复杂的泛型类型(比如Map<Long,Map<Integer,String>>
)我在一个类中内部使用。 (没有外部可见性;它只是一个实现细节。)我想在typedef中隐藏它,但Java没有这样的功能。
昨天我重新发现了以下习语,并且感到很失望,因为它是considered an anti-pattern 。
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对使用它的主要反对意见)是否有任何理由呢?
答案 0 :(得分:10)
实际上,大多数反模式都是微妙的。例如,链接的文章解释了伪typedef如何导致API类型签名过于严格,与特定的实现决策,病毒等相关联。但这完全是在公共API的背景下。如果你将伪typedef保留在公共API之外(即将它们限制在一个类,或者可能是一个模块),它们可能没有真正的伤害,并且它们可能使你的代码更具可读性。
我的观点是,你需要理解反模式并做出推理判断关于何时何地避免它们。只是采取“我将从不做X而因为它是一种反模式”的立场意味着有时你会排除可接受的,甚至是好的解决方案。
答案 1 :(得分:5)
真正的问题是这个成语在伪typedef 和客户端代码之间创建了一个高度耦合。但是因为您私下使用FooBarMap
,所以没有真正的耦合问题(它们是实现细节)。
<强> NB 强>
现代Java IDE应该有助于处理复杂的泛型类型。
答案 2 :(得分:2)
对于公共接口,我不喜欢看泛型类型,因为它们没有意义。让我看到一个带有HashMap参数的方法&lt; Long,Map&lt; Integer,String&gt;&gt;就像foo(int,int,int,void *,int)之类的C方法一样。拥有一个真正的类型只会使代码更容易阅读。对于公共接口,最好创建包装HashMap的FooBarMap&lt; Long,Map&lt; Integer,String&gt;&gt;而不是'typedef',但对于课堂内部使用,我看不到任何缺点。
答案 3 :(得分: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{ };
但它变得越来越麻烦。
答案 4 :(得分:0)
在将其置于公共界面时,他对此有一个很好的观点。这个成语模仿某种形式的语法糖,它不应该影响你向客户展示的东西。
但我认为没有充分的理由不在本地使用它,只要它让你的生活更轻松,代码更具可读性 - 而且你知道自己在做什么。布莱恩可以在任何情况下对其进行概括和强烈建议,但这是他的哥特感觉:p
答案 5 :(得分:0)
如果您只在一个小的本地化代码单元中使用它,那么问题就很小,是真的。
事情是,收益也是如此:你的程序可能甚至不会在文本上变小,直到你引用伪typedef 5次,这意味着它可见的区域必须是非平凡的。
我可能不会重写执行此操作的代码,但这似乎是一个不好的习惯。