将对象向下转换为接口

Downcasting object to interface

简而言之,我希望能够通过未实现特定接口的 superclass 对 class 个实例进行分组。但是从实例集中,我想从实现该接口的那些实例上的接口调用方法。

可能会解释它的一些示例代码。

class Building{
  String c = "white"; 
  Building(){
  }

  void printColor(){
    println("The building is " + c);
  }

  void paint( String c ){
   this.c = c;  
  }

  void printBuildQuality(){
   println("The build quality is average"); 
  }
}


class SturdyFactoryBuilding extends Building implements Factory{

 SturdyFactoryBuilding(){
  super(); 
 }

 void printBuildQuality(){
  println("The build quality is sturdy"); 
 }

 void printFactoryOutput(){
  println("This factory makes stuff"); 
 }
}

class ShakyFactoryBuilding extends Building implements Factory{

  ShakyFactoryBuilding(){
   super(); 
  }

  void printBuildQuality(){
   println("The build quality is shaky");
  }

  void printFactoryOutput(){
   println("This factory makes slightly different stuff"); 
  }
}


public interface Factory{

  public void printFactoryOutput();

}

 Building building = new SturdyFactoryBuilding();    
 building.printBuildQuality();
 building.printColor();
 building.paint("bright red");
 building.printColor();
 building.printFactoryOutput();  

有什么方法可以实现这一点,也许是通过在 superclass 中设置一个 'isFactory' 标志。

谢谢。

我认为你必须做出权衡:要么接受一些反模式,要么打开你 Building "interface" 充当适配器:

class Building implements Factory{

    // the other building stuff

    @Override
    public void printFactoryOutput(){ /* NO OP */ }
}

然后您可以在所有 Building 上调用 printFactoryOutput,到目前为止没有任何效果。

由于您的 Factory 实现扩展了 Building 它们自动继承了 NOOP 实现。但是既然你覆盖了它:

class ShakyFactoryBuilding extends Building implements Factory{

  ShakyFactoryBuilding(){
   super(); 
  }

  @Override
  public void printBuildQuality(){
   println("The build quality is shaky");
  }

  @Override
  public void printFactoryOutput(){
   println("This factory makes slightly different stuff"); 
  }
}

...你得到了想要的结果。

缺点当然是所有建筑物都printFactoryOutput可见。但这就是我所说的权衡。如果这是不可接受的,您将不得不完全重新考虑您的设计。

为了明确不是工厂的建筑物不应调用该方法,您可以在建筑物中抛出 UnsupportedOperationException,但这会强制 try/catch 块在你的代码中无处不在。你也可以 return 一个布尔值:default=false 和 returning true 如果实际上是一个工厂......有很多可能性。

您也可以更改设计以使用 composition over inheritance

我想你得到的信息是这是个坏主意。它违反了公认的面向对象设计原则。也就是说,有几种方法可以解决这个问题,有些方法比其他方法不那么令人讨厌。

直接施放

最简单的事情是这样的:

if (building instanceof Factory)
    ((Factory)building).printFactoryOutput();

您正在检查它是否是 Factory,然后在转换后调用特定于 Factory 的方法。这是实现糟糕设计的一种直接(因此也很容易理解)的方式。

Building 知道 Factory

这有问题,因为目前 BuildingFactory 之间没有必要的关系,但这样的关系可能会帮助你。

class Building {
    // ...
    Factory adaptToFactory() {
        return null;
    }
}

class SturdyFactoryBuilding ... {
    // ...
    @Override
    Factory adaptToFactory() {
        return this;
    }
}

ShakyFactoryBuilding 类似。

然后你可以写

Factory f = building.adaptToFactory();
if (f != null)
    f.printFactoryOutput();

更通用的适配器

如果你经常做这种事情,你可以把它变成一个模式,你可以在任何需要的地方应用。 (例如,Eclipse 到处都使用适配器。)

interface Adaptable {
    <T> T adapt(Class<T> clazz);
}

class Building implements Adaptable {
    // ...
    @Override
    <T> T adapt(Class<T> clazz) {
        if (clazz.isInstance(this)) {
            return clazz.cast(this);
        }
        return null;
    }
}

然后你会写

Factory f = building.adapt(Factory.class);
if (f != null)
    f.printFactoryOutput();

还有很多地方可以解决这个问题,但我认为这对这个问题来说已经足够了。