方法链:如何在多级继承中使用getThis()技巧

7

我的问题涉及方法链 + 继承不兼容?。 但不幸的是,所有方法链的示例/答案都只使用了单级继承。 我的用例涉及多级继承,例如

abstract class PetBuilder{...}
class  DogBuilder extends PetBuilder{..}
class DogType1Builder extends DogBuilder {...}

构建一个Dog对象,我将使用DogBuilder或DogType1Builder。
如何针对上述用例使用getThis技巧?
我想使用构建器模式来构建一个复杂的Dog对象(Dog对象模型)。DogType1将有一些额外的属性。
因此,为了使用getThis Trick,上述类的声明将变成:
abstract class PetBuilder<T extends PetBuilder<T>>
class DogBuilder<T extends DogBuilder<T>> extends PetBuilder<DogBuilder<T>>
class DogType1Builder extends DogBuilder<DogType1Builder>

现在这样做会出现两个问题。
1. 'DogBuilder'中的构建器方法将如下所示。
public T someMethodInDog(String dogName) {
..
return (T)this; ///i dont want type casting and i cant use getThis Trick Here (compiler reports error for conversion from DogBuilder to T)
}

2.由于DogBuilder已经参数化,因此要创建“DogBuilder”的实例,我将不得不使用

DogBuilder<DogBuilder> builder=new DogBuilder(); //passing <DogBuilder> type ...real pain

有更好的方法吗?

2
你实际上尝试过吗?我不认为同样的技巧在多层继承中不起作用。如果你有具体问题,请澄清并最好给出一个具体的代码示例。 - Péter Török
我已经编辑了我的问题以澄清问题。 - harrybvp
2个回答

8
你的问题根源在于类设计问题:你试图继承一个具体类,这几乎总是一个错误,并且(你的例子)会导致许多问题。按照所提供的例子,你不应该实例化Dog,因为在这样的宇宙中,一般不存在Dogs,就像不存在Pets一样——只有Poodles、NewFoundlands、Spaniels等。因此,getThis不应该在中级(抽象)类中实现,而只应该在(具体)叶子类中实现。在所有中级抽象类中,你只应该引用通用类型参数T,而不是实际的类名。
以下是根据上述规则重新编写的参考线程的答案示例
public class TestClass {

  static abstract class Pet <T extends Pet<T>> {
    private String name;

    protected abstract T getThis();

    public T setName(String name) {
      this.name = name;
      return getThis(); }
  }

  static class Cat extends Pet<Cat> {
    @Override protected Cat getThis() { return this; }

    public Cat catchMice() {
      System.out.println("I caught a mouse!");
      return getThis();
    }
  }

  // Dog is abstract - only concrete dog breeds can be instantiated
  static abstract class Dog<T extends Dog<T>> extends Pet<T> {
    // getThis is not implemented here - only in concrete subclasses

    // Return the concrete dog breed, not Dog in general
    public T catchFrisbee() {
      System.out.println("I caught a frisbee!");
      return getThis();
    }
  }

  static class Poodle extends Dog<Poodle> {
    @Override protected Poodle getThis() { return this; }

    public Poodle sleep() {
      System.out.println("I am sleeping!");
      return getThis();
    }
  }

  static class NewFoundland extends Dog<NewFoundland> {
    @Override protected NewFoundland getThis() { return this; }

    public NewFoundland swim() {
      System.out.println("I am swimming!");
      return getThis();
    }
  }

  public static void main(String[] args) {
    Cat c = new Cat();
    c.setName("Morris").catchMice();
    Poodle d = new Poodle();
    d.setName("Snoopy").catchFrisbee().sleep();
    NewFoundland f = new NewFoundland();
    f.setName("Snoopy").swim().catchFrisbee();
  }
}

1
很不幸,我也想构建“DogBuilder”。 - harrybvp
1
有没有一种方法可以让ZombiePoodle扩展Poodle并使其工作:ZombiePoodle zp = new ZombiePoodle().sleep();而不覆盖sleep()?这样一个具体类继承另一个具体类。 - Aquarius Power
1
我找到了:Poodle<P extends Poodle<P>> extends Dog<P>ZombiePoodle extends Poodle<ZombiePoodle> - Aquarius Power
@AquariusPower:很好,但现在怎么才能 new Poodle() 呢?不能使用 new Poodle<Poodle>() - Bertie
1
@bertie 我刚刚执行了 Poodle p = new Poodle();,它可以运行,这里是代码,但阅读起来可能有点困难:`public class TestPoodle { static class Poodle <P extends Poodle>{public void tstSleep(){};} static class ZombiePoodle <P extends ZombiePoodle> extends Poodle<P>{} static class UltraZombiePoodle <P extends UltraZombiePoodle> extends ZombiePoodle<P>{} public static void main(String[] args) { Poodle p = new Poodle(); p.tstSleep(); UltraZombiePoodle uzp = new UltraZombiePoodle(); uzp.tstSleep(); } } ` - Aquarius Power
显示剩余2条评论

2
我不相信你可以在多级继承中使用“getThis”技巧。你有超类“Pet >”,第一个子类“Dog extends Pet”,第二个子类“Poodle extends Dog”。使用“getThis”技巧,你有方法“protected T getThis()”和像“public T rollOver()”这样的方法。这意味着“Poodle”和“Dog”都有方法“protected Dog getThis()”和“public Dog rollOver()”。
我会遵循Michael Myers' suggestion建议使用协变返回类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接