Kevin
Kevin

Reputation: 6292

Best way to write a java object with a lot of optional properties

I have to write a Java object which is used to hold calculation results. The results contains a large number of fields which may or may not be set depends on the type of algorithm used. For example:

class EquityValuationResult {
    private ValuationAlgorithm algorithm;
    private int yield;
    private double curve;
    private double meanValue;
    private double probability;
    private int standardDeviation;
    private boolean approximateValue;
    ......
    //Getter and Setters

}

For different ValuationAlgorithm, the contents of these properties may be different. For example, if the algorithm is A, yield and probability will contain the calculation value, the rest of those will be null; if the algorithm is B, standardDeviation and curve will contain the result and the rest of those will be null, etc. The rule is very complicated, for example, if approcimateValue is true, some of the value will be overridden etc. Therefore, all these properties have to be in one class as they logically is one result.

An alternative way to do this is to use a Map

class EquityValuationResult {
    private final String YIELD = "yield";
    private final String CURVE = "curve";
    ........

    private ValuationAlgorithm algorithm;
    private final Map<String, Object> result = new HashMap<String, Object>();

    // Getter and Setters
}

But if I do it like this, the getter and setter has to convert the values from Object to corresponding data type. I also have to define those constants and use them as the key of the map, this looks too cumbersome.

Which will be the better way in your opinion? Are there any other better way to do this?

EDIT: Forgot to mention, creating separate class for each calculationType is not an option due to constraints. I have to use one class.

Upvotes: 8

Views: 11655

Answers (3)

TechTrip
TechTrip

Reputation: 4537

@Joel had a comment that set off a lightbulb here. Java 8 has an Optional just for this purpose.

To see how to apply the example you can read about it here, perhaps this would work best.

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

For example:

import java.util.Optional;

public class Result {
    final CalculationType calculationType;
    private Optional<Integer> yield = Optional.empty();
    private Optional<Double> curve = Optional.empty();
    private Optional<Double>  meanValue = Optional.empty();
    private Optional<Double>  probability = Optional.empty();
    private Optional<Integer>  standardDeviation = Optional.empty();

    public Result(CalculationType calculationType) {
        this.calculationType = calculationType;
    }

    public CalculationType getCalculationType() {
        return calculationType;
    }

    public Optional<Integer> getYield() {
        return yield;
    }

    public Optional<Double> getCurve() {
        return curve;
    }

    public Optional<Double> getMeanValue() {
        return meanValue;
    }

    public Optional<Double> getProbability() {
        return probability;
    }

    public Optional<Integer> getStandardDeviation() {
        return standardDeviation;
    }

}

Upvotes: 1

TechTrip
TechTrip

Reputation: 4537

Forget the map example if you are allowed to create a helper or something. Under this restriction I might write an enum as a helper/type to identify and perhaps a mapper to preserve order based on type.

As a helper method inside your result class perhaps:

public double[] getCalcValues(){
    switch (calculationType){
    case A:
        // do something
        return null;
    case B:
        // do something
        return null;
    default:
        throw new RuntimeException("Not Really Possible");
    }
}

This is hopefully possible due to an enum type for CaclulationType. For example:

public enum CalculationType {
    A("A"), B("B");

    final String calcType;

    private CalculationType(String calcType) {
        this.calcType = calcType;
    }

  // ... other enum stuff
}

In that case I may make the enum final for instantiation and make use of the static helper method for cal value extraction and intentionally leave getters off the main class unless somebody pulling off nulls is ok. I left in a getter for the enum in case you needed it elsewhere, if not then I guess I would leave that out as well.

public class Result {
    final CalculationType calculationType;
    private int yield;
    private double curve;
    private double meanValue;
    private double probability;
    private int standardDeviation;

    public Result(CalculationType calculationType) {
        this.calculationType = calculationType;
    }

    public CalculationType getCalculationType() {
        return calculationType;
    }

    public double[] getCalcValues(){
        switch (calculationType){
        case A:
            // do something
            return null;
        case B:
            // do something
            return null;
        default:
            throw new RuntimeException("Not Really Possible");
        }
    }   

    // Only include setters below, force users to use getCalcValues as an extraction class
}

Upvotes: 0

nmore
nmore

Reputation: 2593

Maybe one option is to create an enum class which represents the variable names:

public enum ResultKey {

    YIELD,
    CURVE,
    MEAN_VALUE,
    ...

    // you can add getValue(Map<ResultKey, Object> map) and
    // setValue(Map<ResultKey, Object> map, Object value) methods

}

Then in your result class have a map:

class EquityValuationResult {

    private ValuationAlgorithm algorithm;
    private Map<ResultKey, Object> result = new HashMap<>();

    // Getter and Setters
}

So it is essentially like your map idea, but with an enum.

Upvotes: 1

Related Questions