【问题标题】:How To Cast An Inherited Encapsulated Property To Expose Methods Of Subclass - Java如何强制转换继承的封装属性以公开子类的方法 - Java
【发布时间】:2012-09-27 08:11:17
【问题描述】:

在 Java 中,我有一个抽象基类,比如 WrapX,它包含一个类型的属性,比如 X(想想装饰器 DP)。这个类提供了一个方法来调用封装的X上的特定方法:

public abstract class WrapX{

  protected X instance;

  public WrapX(X x){
     this.instance = x;
  }

  public void foo(){
       instance.foo();
  }

}

public class X {

   public void foo(){
       System.out.println("foo");
   }
}

然后有一个名为Y 的类从X 扩展并提供了一个附加方法:

public class Y extends X {

  public void bar(){
     System.out.println("bar");
  }
}

然后我自然地创建了WrapY,它可以用作Y 类型之上的装饰类型:

public class WrapY extends WrapX{

  ...

  public void bar(){
    instance.bar();
  }

}

所以这就是问题所在。 WrapY 从其父 WrapX 继承了 X 类型的 instance 属性。就 Eclipse 而言,instance 的类型为 X,因此会抱怨它不包含方法 .bar()

当然很公平,但是在这个子类中,我们如何才能将instance 隐式转换为Yinstance(初始类型X 的有效子类)...无需显式的演员属性乱扔代码,或变量阴影?

如果我只是在构造函数中有这个:

public WrapY(Y y){
 this.instance = y;
}

Eclipse 仍然抱怨.bar() 不是X 类型的方法,因为我猜它不能确定WrapY(Y y) 将在构造WrapY 实例之前使用:

public void bar(){
        instance.bar(); // ERROR
      }

这是我目前的方法,到处都是演员:

public WrapY(Y y){
 (Y)instance = y;
}

public void bar(){
  ((Y)instance).bar();
}

在我之前的经验中,我没有遇到过这种特殊类型的架构问题,请将其归档在“基于装饰器的继承类型铸造”下(!)...请告诉我如何建模以更好的方式。

另一个问题是,如果将来有人扩展WrapY,他们的类继承的实例类型将是X 的自然(未转换)类型,而他们可以合理地假设它应该是Y 类型.

谢谢

【问题讨论】:

    标签: java eclipse inheritance casting decorator


    【解决方案1】:

    你可以让你的 Wrap 类通用,例如:

    public abstract class Wrap<T extends X>{
    
        protected T instance;
    
        public Wrap(T x){
            this.instance = x;
        }
    
        public void foo(){
           instance.foo();
        }
    }
    
    
    
    public final class WrapY extends Wrap<Y> {
    
        public WrapY(Y y) {
            super(y);
        }
    
        public void bar(){
            instance.bar();
        }
    }
    

    那么对于WrapY 的实例,instance 将是Y


    更新: 如果您也想从 WrapY 继承(并解决最合适的包装类型的最后一个问题),请执行以下操作:

    public class WrapY<U extends Y> extends Wrap<U> {
    
        public WrapY(U y) {
            super(y);
        }
    
        public void bar(){
            instance.bar();
        }
    }
    

    【讨论】:

    • 感谢您的意见,我喜欢这个主意。但是,如果我添加了从WrapY extends WrapX&lt;Y&gt; 扩展而来的WrapZ,那么在WrapZ 中T 仍然是Y 类型。如果我有WrapZ extends WrapX&lt;Z&gt;,那么WrapZ 将不在继承层次结构中的正确位置,即。它不会从WrapY 继承(因此不会从WrapY 继承方法/属性。你将如何解决这个问题?我需要使所有类都通用吗?例如WrapY&lt;T extends Y&gt; extends WrapX&lt;Y&gt; 这样我就可以拥有WrapZ extends WrapY&lt;Z&gt;? 谢谢
    • 完美!非常感谢,这比我当前的实现要干净得多。特别是考虑到一些类有相当多的方法!不过出于兴趣,如果 WrapY 是最终的,我不能从它扩展吗?它需要是最终的吗?
    • @HodeCode: sorry 'bout the copy&paste-error: 在第二种情况下,你将 WrapY 泛化为能够继承它——所以 final 没有多大意义。
    • @DaveBall 不用担心,我也很怀疑!非常感谢您为 MattR 的出色解决方案做出贡献
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-16
    • 2012-04-21
    • 2010-11-20
    • 2021-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多