将对象向下转换为接口
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
这有问题,因为目前 Building
和 Factory
之间没有必要的关系,但这样的关系可能会帮助你。
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();
还有很多地方可以解决这个问题,但我认为这对这个问题来说已经足够了。
简而言之,我希望能够通过未实现特定接口的 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
这有问题,因为目前 Building
和 Factory
之间没有必要的关系,但这样的关系可能会帮助你。
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();
还有很多地方可以解决这个问题,但我认为这对这个问题来说已经足够了。