2

I'm writing a class which will make time consuming calculations on parametres stored in a list of MyObjects. Since I wanted to have easy access to a number of List's features, I decided to write it extending a list type (an alternative would be to have a List as one of the fields in my class and rewrite all methods I'm going to use, but it looks like an overcomplication). Since the calculations are pretty complex and time consuming, while the result depends solely on the stored parameters (no time influence, no hidden dependencies, etc), I decided to cache the result. So my code looks more or less like this:

public class Calculator extends ArrayList<MyObject> {

   private double Result = Double.NaN; 

   public double getResult() {
        if (Double.isNaN(Result)) {
            Result = CalculateResult();
        }
        return Result;
    }
}

This way, when the method getResult() is called for the first time it calculates the result, stores it, and then reuses during subsequent calls.

Now, the list's contents can be modified with various methods, and many modifications should clear the cache. To achieve this, normally I would write something like:

public void add(MyObject newvalue) {
    super.add(newvalue);
    Result = Double.NaN;
}

However, it does not work, because "super" refers to the generic ArrayList class, so the compiler produces a type error.

An obvious trick on my level would be to create an interim class, which would implement ArrayList of MyObject and make Calculator extend this interim class:

public class MyArrayList extends ArrayList<MyObject> {
}

public class Calculator extends MyArrayList {
}

But it looks like an overcomplication again. Isn't there a more elegant method to achieve this result? Or perhaps, is there a mechanism similar to trigger in SQL, which would force my class clear the cache whenever any modification is made to the List?

Yair Nevet
  • 12,725
  • 14
  • 66
  • 108
Jasio
  • 275
  • 1
  • 7
  • 3
    Don't extend a list implementation. This will pollute your API and forever wire the class to that specific implementation. Use it as a field and implement the `List` interface on your class, then delegate the methods you need to the instance of the list implementation used as a field. It's a little verbose but much more flexible and cleaner to the users of your class. – toniedzwiedz May 17 '14 at 06:29
  • See http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance – Raedwald May 17 '14 at 09:04
  • Thank you all very much for your prompt responces. Your examples indeed fixed the compilation issue. However indeed, it seems that I need to rethink the rationales behind the code design as well. – Jasio May 17 '14 at 12:31

2 Answers2

3

The method add should return boolean value, so all what you need to do is

public boolean add(MyObject newvalue) {
    boolean retVal = super.add(newvalue);
    Result = Double.NaN;
return retVal ;
}
iTech
  • 18,192
  • 4
  • 57
  • 80
user902383
  • 8,420
  • 8
  • 43
  • 63
  • This will fix the compiler error, and I upvoted. However, the other comments about preferring composition over inheritance stand: it would be better to have the ArrayList as a member variable rather than as a superclass. – Warren Dew May 17 '14 at 06:43
1

This is a good example as to when composition over inheritance really makes sense for code design. Your class will become cluttered with unnecessary operations, when it only really needs to have an instance of a List of some kind floating around. It also means that you're not hard-dependent on the ArrayList implementation; for instance, what if your algorithms called for a LinkedList instead?

But, if you really want to fix what you have...

First and foremost, the reason you're getting the compiler error is because, as far as Java is concerned, you're trying to override the add method, but don't quite have the signature right.

The correct signature is specified as boolean add(E), but you're overriding it with a signature of void add(E). The types don't match, so you won't get a successful override, and Java will not compile the class, as you can see.

Next, creating more classes to accomplish the same thing as inheriting and properly overriding the ArrayList class will not gain you anything; if anything, it will be more of an overcomplication.

Makoto
  • 104,088
  • 27
  • 192
  • 230