【问题标题】:Method Chaining: How to use getThis() trick in case of multi level inheritance方法链:在多级继承的情况下如何使用 getThis() 技巧
【发布时间】:2012-03-28 03:50:16
【问题描述】:

我的问题是在Method chaining + inheritance don’t play well together? 的上下文中。 但不幸的是,方法链接的所有示例/答案都使用单级继承。 我的用例涉及多级继承,例如

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

要构造一个 Dog 对象,我将使用 DogBuilder 或 DogType1Builder

如何在上述用例中使用 getThis 技巧?

我想用builder模式来构造一个复杂的Dog对象(Dog Object Model)”。 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>

现在这会产生两个问题

'DogBuilder' 中的 1.builder 方法看起来像

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

有没有更好的方法?

【问题讨论】:

  • 你真的试过了吗?我看不出为什么同样的技巧不应该适用于多层次的继承。如果您有具体问题,请澄清并 - 最好 - 给出一个具体的代码示例。
  • 我已经编辑了我的问题以澄清问题

标签: java generics inheritance method-chaining


【解决方案1】:

我不相信您可以使用getThis 技巧进行多级继承。您有超类Pet&lt;T extends Pet&lt;T&gt;&gt;、第一个子类Dog extends Pet&lt;Dog&gt; 和第二个子类Poodle extends Dog。使用getThis 技巧,您就有了protected T getThis() 方法和public T rollOver() 之类的方法。这意味着PoodleDog 都有protected Dog getThis()public Dog rollOver() 方法。

我会按照Michael Myers' suggestion 使用协变返回类型。

【讨论】:

    【解决方案2】:

    您的问题的根源是类设计问题:您试图从具体类继承,这几乎总是一个错误,并且(您的例子)必然会导致许多问题。为了坚持引用线程中给出的示例,您不应该实例化Dog,因为在这样的宇宙中,一般不存在Dogs,不超过Pets - 只有Poodles, NewFoundlands、Spaniels 等。因此,getThis 不应该在中级(抽象)类中实现,只能在(具体)叶类中实现。并且在所有中级抽象类中,您应该只引用泛型类型参数T,而不是实际的类名。

    下面是the answer to the referred thread中的例子,按照上面的规则重写:

    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();
      }
    }
    

    【讨论】:

    • 实际上我所有的类都充当构建复杂对象(宠物对象模型)的构建器。所以该对象的一些构建器属性是通过 DogBuilder 公开的,我想在 DogType1Builder (它本身有更多的构建器属性)中重用它,这是一个公平的要求。由于我的宠物对象模型有一个复杂的对象图,所以我想使用构建器模式来构建它。
    • 不幸的是,我也想构建“DogBuilder”。
    • 有什么方法可以让ZombiePoodle extends Poodle 和这个工作:ZombiePoodle zp = new ZombiePoodle().sleep(); 不覆盖sleep()?所以,一个具体的延伸另一个。
    • 我找到了:Poodle&lt;P extends Poodle&lt;P&gt;&gt; extends Dog&lt;P&gt;, ZombiePoodle extends Poodle&lt;ZombiePoodle&gt;
    • @bertie 我刚刚做了Poodle p = new Poodle(); 并且它有效,这里是代码,但会有点难以阅读:public class TestPoodle { static class Poodle &lt;P extends Poodle&gt;{public void tstSleep(){};} static class ZombiePoodle &lt;P extends ZombiePoodle&gt; extends Poodle&lt;P&gt;{} static class UltraZombiePoodle &lt;P extends UltraZombiePoodle&gt; extends ZombiePoodle&lt;P&gt;{} public static void main(String[] args) { Poodle p = new Poodle(); p.tstSleep(); UltraZombiePoodle uzp = new UltraZombiePoodle(); uzp.tstSleep(); } }
    猜你喜欢
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多