【问题标题】:Java - Inherited Fluent method return type to return incident class' type, not parent'sJava - 继承的 Fluent 方法返回类型以返回事件类的类型,而不是父类的类型
【发布时间】:2012-10-18 14:11:53
【问题描述】:

当您采用流畅的方法时,您可能会遇到以下情况:

public class Foo<T extends a>{

    public Foo<T> someMethod(){
          System.out.println("foo");
          return this;
    }

}


public class Bar<T extends b> extends Foo<T> {

         public Bar<T> barMethod(){

            System.out.println("bar");
            return this;
         }

}


public class a{}
public class b extends a{}

流畅接口的一个优点是您可以链接方法调用,但是虽然 Bar 继承了 someMethod(),但返回类型是 Foo 而不是 Bar,这会破坏以下链接:

new Bar<b>().someMethod().barMethod();

一个答案可能是为每个继承的方法添加@Overrides,这样 Bar 就有了额外的方法:

 @Override
 public Bar<T> someMethod(){
          System.out.println("foo");
          return this;
    }

但在大类和扩展类层次结构中,这肯定会证明是一团糟?!是否有适当的返回类型可以赋予流畅的方法,使得每个继承它的类都将返回其特定类型的对象(这样我们就可以在没有强制转换的情况下链接方法)?

我试过了:

        public <U extends Foo<T>> U someMethod(){
          System.out.println("foo");
          return this;
    }

唉,没用。我希望有人知道这个问题的简单而优雅的解决方案。该项目很大,因此如果可能,它需要可维护和可扩展。

感谢您在这种情况下提供的任何帮助。

【问题讨论】:

    标签: java inheritance fluent


    【解决方案1】:

    您可以做的是定义 barMethod 方法抽象,以便现在您可以在 Foo 类型上调用它。

    public abstract class Foo<T extends a> {
    
        public Foo<T> someMethod() {
            System.out.println("foo");
            return this;
        }
    
        public abstract Foo<T> barMethod();
    }
    

    现在您可以轻松调用

    new Bar<b>().someMethod().barMethod();
    

    【讨论】:

    • 这种方法的问题是它阻止了我们直接实例化 Foo,而我仍然需要能够这样做。
    • @HodeCode。所以你不想添加抽象方法,不想重写,也不想进行类型转换。嗯。如果有办法,将是艰难的。让我们看看是否有人可以提出解决方案。但是,如果您找出所有解决方法,我认为没有解决方法。但我仍然不能确定。
    • 那你就得投了。
    • 真可惜,Java 似乎没有优雅地促进这种架构。我试图让客户尽可能简单地使用该库,而不会出现任何乱七八糟的丑陋代码等。
    • @HodeCode 它是抽象类的理想选择,因为您已经有了它的子类,并且在 Foo 类中具有通用功能。
    【解决方案2】:

    如果您不介意未经检查的演员表,您可以这样做:

    public class Foo<T, F extends Foo<T, F>> {
      public F someMethod() {
        System.out.println("foo");
        return (F) this; // <--- That's the unchecked cast! Tucked safely away.
      }
      public static void main(String[] args) {
        new Bar<String>().someMethod().barMethod();
      }
    }
    
    class Bar<T> extends Foo<T, Bar<T>> {
      public Bar<T> barMethod() {
        System.out.println("bar");
        return this;
      }
    }
    

    就个人而言,我为整个项目全局禁用了未经检查的强制转换警告。

    【讨论】:

    • 但是仍然有一个casting,这是 OP 不想要的。我不知道为什么。嗯。但是这个选角更好。它在一个地方。所以,OP应该没问题。否则主帮助他。 ;)
    • @RohitJain 查看我对上述答案的评论:这是一个可用性问题,试图使其成为一个非常简单的库,供客户使用以包含在他们的项目中。 Marko Topolnik 的解决方案很有趣,而且我没有考虑过。似乎某些描述的演员是不可避免的?
    • @MarkoTopolnik。是的,这就是为什么在我的评论结束时,我补充说它是一个更好的演员,因为它在一个地方。 :)
    • 抱歉,在看到您的评论中的编辑之前已回答。删除我的。
    • 我在使用这种方法时遇到了更多困难......我仍然在质疑它是否真的适用于更深层次的层次结构。
    猜你喜欢
    • 1970-01-01
    • 2020-11-20
    • 2017-10-21
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-19
    相关资源
    最近更新 更多