We've all encountered a situation where changing requirements caused some function that had a single native return type to need to return a second value. One possible solution is to put the two return values in some wrapper class as follows:
class ReturnValues { private int numDays; private String lastName; public ReturnValues(int i, String s) { numDays = i; lastName = s; } public int getNumDays() { return numDays; } public String getLastname() { return lastName; } }
It is trivial to add additional return values to this mechanism. If this is used as the return value to an interface function and you don't have access to change the ReturnValues object itself, you can simply subclass the ReturnValues wrapper to include additional fields as needed and return the base class reference.
Then you see something like this spread out over a codebase and wonder if maybe they should have been just a little less agile and that perhaps a tad more planning was required:
class AlsoReturnTransactionDate extends ReturnValues { private Date txnDate; public AlsoReturnTransactionDate(int i, String s, Date td) { super(i,s); txnDate = td; } public Date getTransactionDate() { return txnDate; } } class AddPriceToReturn extends AlsoReturnTransactionDate { private BigDecimal price; public AddPriceToReturn(int i, String s, Date td, BigDecimal px) { super(i,s,td); price = px; } public BigDecimal getPrice() { return price; } } class IncludeTransactionData extends AddPriceToReturn { private Transaction txn; public IncludeTransactionData(int i, String s, Date td, BigDecimal px, Transaction t) { super(i,s,td,px); txn = t; } public Transaction getTransaction() { return txn; } } class IncludeParentTransactionId extends IncludeTransactionData { private long id; public IncludeParentTransactionId(int i, String s, Date td, BigDecimal px, Transaction t, long id) { super(i,s,td,px,t); this.id = id; } public long getParentTransactionId() { return id; } } class ReturnWithRelatedData extends IncludeParentTransactionId { private RelatedData rd; public ReturnWithRelatedData(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd) { super(i,s,td,px,t,id); this.rd = rd; } public RelatedData getRelatedData() { return rd; } } class ReturnWithCalculatedFees extends ReturnWithRelatedData { private BigDecimal calcedFees; public ReturnWithCalculatedFees(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf) { super(i,s,td,px,t,id,rd); calcedFees = cf; } public BigDecimal getCalculatedFees() { return calcedFees; } } class ReturnWithExpiresDate extends ReturnWithCalculatedFees { private Date expiresDate; public ReturnWithExpiresDate(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed) { super(i,s,td,px,t,id,rd,cf); expiresDate = ed; } public Date getExpiresDate() { return expiresDate; } } class ReturnWithRegulatoryQuantities extends ReturnWithExpiresDate { private RegulatoryQuantities regQty; public ReturnWithRegulatoryQuantities(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq) { super(i,s,td,px,t,id,rd,cf,ed); regQty = rq; } public RegulatoryQuantities getRegulatoryQuantities() { return regQty; } } class ReturnWithPriorities extends ReturnWithRegulatoryQuantities { private Map<String,Double> priorities; public ReturnWithPriorities(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq, Map<String,Double> p) { super(i,s,td,px,t,id,rd,cf,ed,rq); priorities = p; } public Map<String,Double> getPriorities() { return priorities; } } class ReturnWithRegulatoryValues extends ReturnWithPriorities { private Map<String,Double> regVals; public ReturnWithRegulatoryValues(int i, String s, Date td, BigDecimal px, Transaction t, long id, RelatedData rd, BigDecimal cf, Date ed, RegulatoryQuantities rq, Map<String,Double> p, Map<String,Double> rv) { super(i,s,td,px,t,id,rd,cf,ed,rq,p); regVals = rv; } public Map<String,Double> getRegulatoryValues() { return regVals; } }
The icing on the cake is that everywhere the added values are used, the base return type has to be cast to at least the level that contains the needed field.