0

I'm writing a program that keeps track of how many assets a person has. Each person class has an ArrayList of what is called a Value_Item object.

Value_Item is a simple object.

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

I assume the code above is self-explanatory if not happy to clarify anything.

From Value_Item I extend to a few classes, such as Equity, Fund, Cash etc. All of these have their various properties etc, such as Equity "unit price".

My current solution to storing the information is to create a subclass and when I call the superclass constructor set the type of the subclass then when I need to act on the data, say get the unit price of all held funds, I check the type and downcast.

Eg

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

I have however read that downcasting is not favoured, and the solution itself doesn't feel very elegant, is there a better way of doing this java's equivalent of more "pythonic".

  • 6
    Avoid underscores in the variable/class naming. – davidxxx Jul 29 '18 at 18:23
  • 1
    `if (_value_item instanceof Fund) { Fund fund = (Fund) _value_item; ...}` – Johannes Kuhn Jul 29 '18 at 18:24
  • 2
    you should format Java code like Java code not Python if you want Java developers to read it and help with it, just as you would not write Python code with Java naming standards and expect Python developers to read it. –  Jul 29 '18 at 18:40
  • Please read [Why is asking a question on “best practice” a bad thing?](https://meta.stackexchange.com/questions/142353/why-is-asking-a-question-on-best-practice-a-bad-thing/243450) before attempting to ask more questions that are opinion based that invite argumentative discussion because they do not have a single agreed upon answer. –  Jul 29 '18 at 18:40
  • Apologies I didn't realise java and python were so different in formatting, will look up a style guide in the future! – Oliver Cohen Jul 29 '18 at 21:18

1 Answers1

2

I have however read that downcasting is not favoured

Indeed. It should be used only as last resort. Essentially because checking the types of the objects to perform a processing is not maintainable and it also produces a less safe code at compile time as the check type will only occur at runtime.

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

In your case the main issue is that Value_Item represents a too wide concept, it is like if you defined a class ValueForAnyThing.
So hard to use elements of List<ValueForAnyThing> without downcast.

Subclassing even if it is not its main role may be helpful to prevent duplicate code but subclassing may also appear helpless as you want to use the objects of the subclasses in an uniform way but that the base class is too broad.

In case of collections/arrays that declare as element type a common base type, two known ways to prevent downcasting are :

1) Moving the behavior in a base class method.
2) Not gathering all subclasses instances in a same collection/array.


1) Moving the behavior in a base class method.

Suppose that the following extract makes part of a computation that all subclasses do but that each one with its own fields/methods :

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

You could introduce an abstract compute() method in ValueItem :

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

And subclasses will implement it :

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

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

Now you can invoke the compute() method on any elements (or all) of the List :

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

2) Not gathering all subclasses instances in a same collection/array.

You could indeed split the List into multiple parts to group together things that should be manipulated uniformly.

Note also that if multiple kinds of items could be manipulated uniformly you could introduce an interface common to them.
For example, suppose that Equity and Fund could be manipulated uniformly because they belong to a same specific concept : UnitPricable and suppose Cash is a specific concept that has its own way to be represented/manipulated, you could so get something like :

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();               
        ...
     }
   }
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Thanks for the help, makes a lot of sense. I had avoided splitting into separate arrays as wanted to keep the code more straightforward but now see that what you sacrifice is the proper methodology for manipulating them! – Oliver Cohen Jul 29 '18 at 21:21
  • 1
    @Oliver Cohen Glad that it may help you. But it is not the single way. I updated to provide another line of reflection. I am not sure that it will fit your requirement but anyway it is good having the both ways in the mind. – davidxxx Jul 30 '18 at 11:55