我正在编写一个跟踪一个人拥有多少资产的程序。每个人类都有一个称为Value_Item对象的ArrayList。
Value_Item是一个简单的对象。
class Value_Item
{ float _value;
String _currency;
String _type //+getters and setters}
如果不愿意澄清任何内容,我认为上面的代码是不言自明的。
我从Value_Item扩展到几个类别,例如股票,基金,现金等。 所有这些都有其不同的属性,例如权益“单价”。
我当前存储信息的解决方案是创建一个子类,当我调用超类构造函数设置子类的类型时,当我需要对数据采取行动时,比如说获取所有持有资金的单价,我检查类型和垂头丧气。
例如
if(_value_item.getType()=="FUND){
Fund fund = (Fund) _value_item
float unit_price = fund.getUnitPrice()}
但是我读到,向下转换是不受欢迎的,并且解决方案本身并不十分优雅,是否有更好的方法来实现java等效的“ pythonic”。
答案 0 :(得分:2)
不过,我读到偏爱偏向
的确。它只能用作最后的手段。本质上是因为检查对象的类型以执行处理是不可维护的,并且在编译时它还会产生不太安全的代码,因为检查类型只会在运行时发生。
有没有更好的方法来执行此Java等效操作? “ pythonic”。
在您的情况下,主要问题是Value_Item
代表的概念太宽泛,就像您定义类ValueForAnyThing
一样。
很难使用List<ValueForAnyThing>
的元素而不会降低。
即使不是主要的子类,也可能有助于防止重复代码,但是当您希望以统一的方式使用子类的对象但子类太宽泛时,子类也可能显得无助。
对于声明为元素类型为通用基本类型的集合/数组,防止向下转换的两种已知方法是:
1)在基类方法中移动行为。
2)不在同一集合/数组中收集所有子类实例。
1)在基类方法中移动行为。
假设以下摘录构成了所有子类都可以进行的计算的一部分,但是每个子类都有自己的字段/方法:
if(_value_item.getType()=="FUND){
Fund fund = (Fund) _value_item
float unit_price = fund.getUnitPrice()}
}
您可以在compute()
中引入抽象的ValueItem
方法:
public class ValueItem{
public abstract float compute();
// ...
}
子类将实现它:
public class Cash extends ValueItem{
@Override
public float compute(){
// ...
}
// ...
}
public class Equity extends ValueItem{
@Override
public float compute(){
// ...
}
// ...
}
现在您可以在compute()
的任何元素(或全部)上调用List
方法:
for (ValueItem valueItem : valueItems){
float computation = valueItem.compute();
// ....
}
2)不在同一集合/数组中收集所有子类实例。
您确实可以将List
分成多个部分,以将应统一处理的内容组合在一起。
还请注意,如果可以统一操纵多种项目,则可以引入它们共有的界面。
例如,假设Equity
和Fund
可以被统一操纵,因为它们属于相同的特定概念:UnitPricable
并假设Cash
是一个具有自己方式的特定概念要表示/操作,您可以这样获得:
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();
...
}
}
}