从超级对象列表中进行向下转换

Downcasting alternative from a list of super objects

我正在编写一个程序来跟踪一个人拥有多少资产。每个人 class 都有一个所谓的 Value_Item 对象的 ArrayList。

Value_Item 是一个简单的对象。

class Value_Item
{ float _value;
  String _currency;
  String _type //+getters and setters}

如果不想澄清任何内容,我认为上面的代码是不言自明的。

从 Value_Item 我扩展到一些 class ,例如股票、基金、现金等。 所有这些都有其不同的属性等,例如 Equity "unit price".

我目前存储信息的解决方案是创建一个 subclass,当我调用 superclass 构造函数时设置 subclass 的类型,然后当我需要时对数据进行操作,说得到所有持有基金的单价,我检查类型和向下。

例如

if(_value_item.getType()=="FUND){
Fund fund = (Fund) _value_item 
float unit_price = fund.getUnitPrice()}

但是我读到不喜欢向下转型,而且解决方案本身感觉不是很优雅,有没有更好的方法来做到这一点 java 相当于更多 "pythonic"。

I have however read that downcasting is not favoured

确实如此。它应该只作为最后的手段使用。本质上是因为检查对象的类型以执行处理是不可维护的并且它还会在编译时产生不太安全的代码作为检查类型只会在运行时发生。

is there a better way of doing this java's equivalent of more "pythonic".

在你的情况下,主要问题是 Value_Item 代表了一个太宽泛的概念,就像你定义了一个 class ValueForAnyThing.
很难在不沮丧的情况下使用 List<ValueForAnyThing> 的元素。

Subclassing 即使它不是它的主要作用可能有助于防止重复代码但是 subclassing 也可能显得无能为力,因为你想使用 subclass 是一种统一的方式,但是基础 class 太宽泛了。

如果 collections/arrays 将公共基类型声明为元素类型,两种已知的防止向下转换的方法是:

1) 在基础 class 方法中移动行为。
2) 不在同一个 collection/array.

中收集所有子classes 实例

1) 在基础 class 方法中移动行为。

假设以下摘录构成了所有子classes 所做的计算的一部分,但每个子class 都有自己的 fields/methods :

if(_value_item.getType()=="FUND){
  Fund fund = (Fund) _value_item 
  float unit_price = fund.getUnitPrice()}
}

您可以在 ValueItem 中引入抽象 compute() 方法:

public class ValueItem{
    public abstract float compute();
    // ...
}

子classes 将实现它:

public class Cash extends ValueItem{
    @Override
    public float compute(){
       // ...
    }
    // ...
}

public class Equity extends ValueItem{
    @Override
    public float compute(){
       // ...
    }
    // ...
}

现在您可以对 List 的任何元素(或所有元素)调用 compute() 方法:

for (ValueItem valueItem : valueItems){
     float computation = valueItem.compute();
     // ....
}

2) 没有在同一个 collection/array.

中收集所有子classes 实例

您确实可以将 List 分成多个部分,将应该统一操作的内容组合在一起。

另请注意,如果可以统一操作多种项目,则可以引入它们通用的接口。
例如,假设 EquityFund 可以统一操作,因为它们属于相同的特定概念:UnitPricable 并假设 Cash 是一个有自己方式的特定概念成为 represented/manipulated,你可以这样得到:

public class Cash extends ValueItem{
   ...
}

public class Equity extends ValueItem implements UnitPricable{
   ...
}

public class Fund extends ValueItem implements UnitPricable{
   ...
}


public class Person{
   private List<Cash> cashes = new ArrayList<>();
   // the next one groups two kind of subclasses
   private List<UnitPricable> unitPricables = new ArrayList<>();
   ....

   // operations that works on the Cash subclass instances
   public void computeCashes(){
     for (Cash cash : cashes){
        ... = cash.getSpecificCashField();               
        ... = cash.specificCashMethod();               
        ...
     }
   }

   // operations that work on multiple subclasses instances : Fund and Entity
   public void computeUnitPricables(){
     for (UnitPricable up: unitPricables){
        ... = up.getUnitPrice();               
        ... = up.specificUnitPriceMethod();               
        ...
     }
   }
}