您是否曾经发现两个或更多级别的嵌套内部类有所帮助?
更新(11/28):如果考虑枚举类,则第二层嵌套可能是有意义的。在最近的一些重构过程中,我简要地拥有了一个外部类(HTTP客户端),一个内部类(内存缓存),以及在内部类中的枚举类(用于缓存逐出策略)。这似乎还不错,但根据@Thorbjørn的观点,我继续提取缓存类及其内部枚举类,将它们从HTTP客户端类中提取出来。
没有。
一个类内部的标准示例是Builder,其中你有一个子类来帮助创建一个正确的实例,给定了许多可能的配置方法。
个人认为,更复杂的嵌套类是需要重构的优秀示例。
如果您从一些数据中生成代码,嵌套类可以是避免名称冲突的好方法。
我个人没有遇到过需要超过一个的情况。我可以想象两个可能会有用。然而,我很难想象超过两个的情况。
我想象的例子是在Java GUI代码中。在某些情况下,将类嵌套在已经嵌套的ActionListener中可能是有用的。
我知道我在回收旧线程,但这对我来说是新的 :)
我们使用多个级别的POJO来反序列化JSON(使用Jackson)。这里是一个我们可能从RESTful web服务返回的JSON的微小示例(虚构):
{ success: true, response: {
sales: { item: "123", sales: 3, returns: 1 },
inventory: { item: "567", qty: 100 }
}
}
我们过去的POJOs设置如下:
public class Json1 {
private boolean success;
private JsonResponse response;
}
public class Json1Response {
private JsonResponseSales sales;
private JsonResponseInventory inventory;
}
public class Json1ResponseSales {
private String item;
private int sales;
private int returned;
}
public class Json1ResponseInventory {
private String item;
private int qty;
}
请注意,这个相对简单的例子给我们带来了四个类文件。现在将其乘以数百个,再乘以一个难度系数3,以应对大多数JSON比这要麻烦得多的事实。成千上万的文件。
字段名称在各个地方被重复使用,并且同一个字段名称可能根据Web服务的不同而具有不同的内容。(想象一下数量可能从一个Web服务返回为字符串,从另一个Web服务返回为整数,然后将其乘以数百个。)
public class Json1 {
private boolean success;
private JsonResponse response;
public class Json1Response {
private JsonResponseSales sales;
private JsonResponseInventory inventory;
public class Json1ResponseSales {
private String item;
private int sales;
private int returned;
}
public class Json1ResponseInventory {
private String item;
private int qty;
}
}
}
我看到了嵌套类的层数使用情况。
有一台名为Tandem(来自HP)的遗留机器,最初运行COBOL/C代码。后来有“补丁”使该机器能够运行Java。COBOL的变量结构通常是多层的(甚至5层也很常见),因此为了让Java能够调用COBOL服务器,Java类也是多层的,以简化它们之间数据的转换。
我同意这是一个非常不寻常的情况,但无论如何...
当然 - 这有时是有效的。我刚刚几分钟前就做了一些。
例如,在我编写的某些测试代码中,我想设置一些样板文件来处理运行多个可调用项。这个样板需要创建多个可调用代码块的实例。在这个例子中,我正在创建一个工厂的实例以传递到threadedTest,并且该工厂创建新的可调用项。
@Test public void testXXXXXXXX() throws Throwable {
threadedTest(new CallableFactory() {
@Override public Callable<Request> create() {
return new Callable<Request>() {
// might have state
@Override public Request call() throws Exception {
// do the steps for this test
return ...;
}};
}});
}
比创建两个新类更简洁,其中一个只是创建另一个。当然,在你习惯这种风格之前,这里会有可读性的惩罚...
如果将此与模板方法结合使用以控制事务或数据库连接/关闭,可能会达到三层深度。(我有一些类似的代码;如果你这样做,请确保在注释中编写一个虚拟示例并解释结构)