java - 我可以在不执行不安全操作的情况下使用方法链接在java中创建抽象构建器类吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5818504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 12:55:27  来源:igfitidea点击:

Can I have an abstract builder class in java with method chaining without doing unsafe operations?

javagenericsbuilderfluent-interface

提问by Patrick Huy

I'm trying to have an abstract base class for some builder classes so I can easily reuse code between the Builder implementations. I want my builders to support method chaining therefore a method has to return "this" instance of the most specific type. I figured I could probably do this with generics. Unfortunatly I did not manage to do it without using unsafe operations. Is it possible?

我正在尝试为一些构建器类创建一个抽象基类,以便我可以轻松地在构建器实现之间重用代码。我希望我的构建器支持方法链,因此方法必须返回最具体类型的“这个”实例。我想我可能可以用泛型来做到这一点。不幸的是,如果不使用不安全的操作,我就无法做到这一点。是否可以?

Sample code of how I'm trying it (and how it works) below. I'd like to avoid casting to T in "foo()" (which causes an unchecked warning), can this be done?

下面是我如何尝试(以及它如何工作)的示例代码。我想避免在“foo()”中强制转换为 T(这会导致未经检查的警告),可以这样做吗?

public class Builders
{
   public static void main( final String[] args )
   {
      new TheBuilder().foo().bar().build();
   }
}


abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
   public T foo()
   {
      // set some property
      return (T) this;
   }
}


class TheBuilder extends AbstractBuilder<TheBuilder>
{
   public TheBuilder bar()
   {
      // set some other property
      return this;
   }

   public Object build()
   {
      return new Object();
   }
}

回答by Tom Hawtin - tackline

You want to declare Tas extends AbstractBuilder<T>in AbstractBuilder.

要声明Textends AbstractBuilder<T>AbstractBuilder

Use an abstract protectedmethod to get thisof type T.

使用一种abstract protected方法来获取this类型T

abstract class AbstractBuilder<T extends AbstractBuilder<T>> {
    protected abstract T getThis();

    public T foo() {
        // set some property
        return getThis();
    }
}


class TheBuilder extends AbstractBuilder<TheBuilder> {
    @Override protected TheBuilder getThis() {
        return this;
    }
    ...
}

Alternatively, drop the generic type parameter, rely on covariant return types and make the code cleaner for clients (although usually they would be using TheBuilderrather than the largely implementation detail of the base class), if making the implementation more verbose.

或者,TheBuilder如果使实现更加冗长,则删除泛型类型参数,依赖协变返回类型并使客户端的代码更清晰(尽管通常他们会使用而不是基类的主要实现细节)。

回答by Jason S

One alternative is not to use generics, but use overrides:

一种替代方法是不使用泛型,而是使用覆盖:

abstract class AbstractBuilder
{
   public AbstractBuilder foo()
   {
      // set some property
      return this;
   }
}

class TheBuilder extends AbstractBuilder
{
   @Override public TheBuilder foo()
   {
      super.foo(); return this;
   }
   public TheBuilder bar()
   {
      // set some other property
      return this;
   }

   public Object build()
   {
      return new Object();
   }
}

回答by Mike Thomsen

This should help:

这应该有帮助:

abstract class AbstractBuilder<T extends AbstractBuilder<?>>
{
   public AbstractBuilder<T> foo()
   {
      // set some property
      return (AbstractBuilder<T>) this;
   }

   abstract AbstractBuilder<T> bar();
   abstract Object build();
}