【问题标题】:Best practice to reduce generic variables in type hierarchies?减少类型层次结构中的泛型变量的最佳实践?
【发布时间】:2015-04-21 19:21:19
【问题描述】:

我想知道当包含类型层次结构和许多泛型变量时,是否可以使 java 的泛型更具可读性和/或更易于使用。我还不太熟悉java的泛型。下面的例子可以做什么:

假设我需要以下课程...

abstract class BaseClass<T> {}

...使用以下类的列表...

class Foo<T1, T2> {}

... 并在此类实例上额外提供一个迭代器。

所以我会做以下事情:

class ImplClass<T1, T2> extends BaseClass<List<Foo<T1, T2>>> implements Iterator<Foo<T1, T2>> {}

我们还假设有一个处理 BaseClass 的接口:

interface Manipulator<T, B extends BaseClass<T>> {
  void doSomething(B baseClassInstance);
}

因此,当为 ImplClass 编写实现该接口的类时,我总是不得不再次编写整个泛型签名,不是吗? 所以像:

class ManipulatorA<T1, T2> implements Manipulator<List<Foo<T1, T2>>, ImplClass<T1, T2>> {
  @Override
  void doSomething(ImplClass<T1, T2> baseClassInstance) {...}
}
class ManipulatorB<T1, T2> implements Manipulator<List<Foo<T1, T2>>, ImplClass<T1, T2>> {
  @Override
  void doSomething(ImplClass<T1, T2> baseClassInstance) {...}
}

因此,我可以提供一个 EMPTY 接口,仅用于类型转换以减少泛型变量:

interface ImplManipulator<T1, T2> extends Manipulator<List<Foo<T1, T2>>, ImplClass<T1, T2>>{
  // actually empty
}

并且实现看起来像:

class ManipulatorA<T1, T2> implements ImplManipulator<T1, T2> {
  @Override
  void doSomething(ImplClass<T1, T2> baseClassInstance) {...}
}
class ManipulatorB<T1, T2> implements ImplManipulator<T1, T2> {
  @Override
  void doSomething(ImplClass<T1, T2> baseClassInstance) {...}
}

拥有一堆空接口对我来说似乎不太可读。 也不必一直考虑巨大的通用签名。 在处理这种情况时,我能做些什么来生成更好的代码?

【问题讨论】:

  • 在这种情况下是 Foo&lt;T1, T2&gt; 常量因素还是您要声明例如BaseClass&lt;List&lt;String&gt;&gt; 也是?
  • Well Foo 只是一个非常常用的类型的例子。但这不是一个恒定的因素,所以我也可能会使用一个额外的中间类 ListBaseClass extends BaseClass> implements Iterable 并为此提供一个额外的(空)接口。我猜仍然不会有太大变化。

标签: java generics


【解决方案1】:

在处理这种情况时我能做些什么来生成更好的代码?

更改语言...

java 不支持类型别名或 haskell 样式的新类型。如果可以,请将 scala 添加到您的项目中。你可以混合使用 scala 和 java。

另一种选择是使用某种源生成/预处理。甚至可能使用 AST 变压器。但这将是完全定制的,因此在不确切了解您的情况的情况下很难给您任何建议

如果您必须坚持使用 java,那么正如您所注意到的,给泛型类型取别名的唯一方法是创建一个中间接口或一个类。您可以通过以下方式稍微清理一下:

  • 正确命名它们。 ImplManipulator 没有提供太多信息,但 FooListManipulator 可能会有所帮助
  • 正确放置它们。如果您只创建内部子类,则不要使用空接口创建新文件 - 将其放在子类所在的同一文件中。如果您只在一个包中创建子类,请创建一个类TypeAliases 并将它们放在您的所有接口与包范围内。如果您在全球范围内需要它,请创建一个包 typeAliases,把所有东西都放在那里,然后再也不看那里了

另一种选择是简单地删除泛型。人们经常使用 hamcrest 匹配器这样做,因为它们的长签名会降低可读性。毕竟泛型是为了帮助你,而不是让你的生活更艰难(至少是这样的想法)

【讨论】:

    猜你喜欢
    • 2016-09-14
    • 2013-03-20
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    相关资源
    最近更新 更多