【问题标题】:Storing different ojects in a container that have been extended from the same abstract class将不同的对象存储在从同一个抽象类扩展而来的容器中
【发布时间】:2012-08-05 18:46:41
【问题描述】:

是否可以在单个容器中存储从同一个抽象对象扩展而来的不同对象,并能够访问这些对象的所有自定义字段。让我举一个例子: 假设我有两辆车:福特和本田。由于所有汽车都有重量和颜色,我可以创建以下抽象类:

public abstract class Car{

  private double weight; 
  private String color;

  public Car(){
    this.weight=0;
    this.color="";
  }
  ...getters and 
  ...setters
}

现在假设我的 Ford 类有一个附加字段“radio”,如下所示:

public Ford extends Car(){
private String radio;

public Ford(){
super();
this.radio = "generic";
}
}

同样,Honda 类也有一个自定义字段 'camera'

public Honda extends Car(){
  private String camera;

  public Honda(){
    super();
    this.camera= "analog";
  }
}

是否可以将这些类的实例保存在单个容器中,如下所示。请注意下面的代码有效,但这不是我想要的。请参阅下面的 cmets:

Ford ford = new Ford();
Honda honda = new Honda();
ArrayList<Car> myCars = new ArrayList<Car>();
myCars.add(ford);
myCars.add(honda);

这是我的问题: 当我做myCars.get(0) 时,我得到了一个Car 类的对象(显然)并且我永远无法获得自定义字段radio。当然,我可以执行((Ford) myCars.get(0)) 之类的操作,并且能够看到 radio 字段,但是是否可以创建一个更好的容器来显示所有字段而无需向下转换等,例如: myContainer.get(0) - 将返回 Ford 类,我将可以访问重量、颜色和 radio myContainer.get(1) - 将返回 Honda 类,我将可以访问重量、颜色和 相机

我的预感告诉我,解决方案就在附近,而且是可能的,但我在 Java 方面的专业知识还没有达到。也许我必须对某种泛型或哈希图做些什么?

谢谢你们!!

【问题讨论】:

  • 参考 Joshua Bloch 的 Effective Java,第 29 条:类型安全的异构容器。
  • 谢谢,我会调查的!!目前我对异构容器知之甚少。谢谢领导!!

标签: java inheritance casting polymorphism abstract-class


【解决方案1】:

有多种选择,但没有一种完全符合您的理想。

  • 您可以在 Car 类中添加特定属性的所有 getter,然后返回 Null 或在它们不适用的地方抛出异常。
  • 您可以申请Visitor pattern
  • 您可以创建一个 CarContainer 类来包装您的列表并具有返回特定类型的所有元素的方法,例如List&lt;Ford&gt; getAllTheFords()。通过这种方式,您可以在容器类中隐藏丑陋的演员表。

我根据个人喜好列出了替代方案:-)

【讨论】:

  • 感谢您的快速回复!!为了确保我理解您列表中的第 1 项,让我举一个例子:所以在我的 Car 类中,我将有两个属性和三个方法,对吗?像这样:public abstract class Car{ private double weight; private String color; public Car(){ this.weight=0; this.color=""; } // --- GETTERS public double getWeight(){...} public String getColor(){...} public String getRadio(){...} } 你说的是 getRadio() 方法会看到 car.radio 属性。我理解正确吗?谢谢!!
  • @JavaFan:仅当 Car 确实具有 radio 属性时。您可以将它移到那里并为没有收音机的汽车设置为 Null,或者让 Car.getRadio() 直接返回 Null。
  • 所以从本质上讲,我必须将福特、本田、丰田等的所有属性都包含在一个屋檐下,即汽车抽象类,对吗?
  • 如果不是属性,至少是相应的getter,是的。在某种程度上,您可以选择是否将收音机视为所有汽车的可配置属性,还是仅福特汽车的结构属性。在前一种情况下,我的第一个解决方案是合适的,否则其他的可能会更好。
  • 就我而言,我认为它必须是福特汽车的结构特性。您会推荐原始回复中的第 3 项作为最佳解决方案吗?
【解决方案2】:

myCars.get(0) 确实返回了一个 Ford 对象。除了这仅在运行时已知。问题是要调用car.radio,您需要知道它是福特汽车,如果不是,您就不能调用该方法。所以无论如何你都需要检查类型和演员表。

一种解决方案是将List&lt;Accessory&gt; 字段添加到您的抽象类中。

您现在可以编写如下内容:

Car car = cars.get(0);
if (car.hasAccessories()) {
    car.getAccessory(0).operate();
}

不确定这是否是您的用例所需要的。

【讨论】:

  • 谢谢!!我将探索这个选项。所以你说的是我有一个附件类,它将所有可能的附件作为属性,然后将它用作 Car 对象中的一个字段,对吧?
【解决方案3】:

您可以做的是使用泛型。

您的存储库可以实现这些方法:

public static <T extends Car> T getFromRepository(Class<T> type, Object key) 
public static <T extends Car> boolean addToRepository(Class<T> type, Object key, T value)

然后你可以这样称呼它(假设你已经有了福特的钥匙):

Ford ford = Repository.getFromRepository(Ford.class, fordKey)

当然你可以实现方法来获取给定类型的所有对象等等......

PS:一个简单的替代方案,如果你可以在子类上使用相同的方法是模板方法模式: http://en.wikipedia.org/wiki/Template_method_pattern

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 2019-07-31
    相关资源
    最近更新 更多