I use this blog as a soap box to preach (ahem... to talk :-) about subjects that interest me.

Wednesday, June 22, 2011

Arrays of Functions in Java

A couple of months ago, shortly after publishing the book Sudoku Programming (also see the post in this blog), I asked myself whether I should have written the programs in Java instead of classic C.

I had chosen C because I thought it would be easier for non-programmers to deal with a procedural language rather than with Object Oriented programming, with its class inheritance and operator overloading. But, looking at the number of functions I needed for the C implementation, I began thinking that in Jva the implementation would probably have been simpler. I simply had to re-develop Solver and Generator in Java. I simply had to do it.

One of the first problems I encountered was how to implement in Java an array of function pointers.
I needed it in order to execute in sequence all the puzzle-solving strategies. In C, I had defined a pointer to a function as follows:

typedef void (*f_ptr_t)(void);

This allowed me to define an array of pointers to strategy functions:

f_ptr_t strats[] = {a_strat, another_strat, a_third_strat};
int n_strats = sizeof(strats)/sizeof(f_ptr_t);

All I needed to do to execute the strategies in sequence was then to write a for-loop as follows:

for (int k_strat = 0; k_strat < n_strats; k_strat++) {
  strat[k]();
     }

To do the same in Java, I defined a Strategy class containing the following method:

public void execute() {
  System.out.println("*** " + this.getClass().getName()
    + " does not redefine the method execute()"
    );
    }

Then, I defined all strategies to be subclasses of Strategy and to implement the execute() method. For example:

class aStrat extends Strategy {
  public void execute() {
    //...
    }
  }

Finally, I defined a StrategyArray class as follows:

class StrategyArray {
  protected static final Strategy STRATS[] = {
    new aStrat, new anotherStrat(), new aThirdStrat()
    };
  public static void executeStrategies() {
    for (int kStrat = 0; kStrat < STRATS.length; kStrat++) {
      STRATS[k].execute();
      }
    }
  }

In reality, I grouped the strategies according to their level of complexity and implemented STRATS as a two-dimensional array, with the first index being the level of complexity of the strategies, ranging from 0 to 3. Also, obviously, STRATS didn’t need to be static, but that allowed me to execute the strategies with:

StrategyArray.executeStrategies();

Instead of having to create a StrategyArray object as in:

StrategyArray strats = new StrategyArray();
strats.executeStrategies();

You might wonder why I didn’t define the Strategy class and its execute method to be abstract, instead of defining a method that displays an error message on the console if it is not overriden. The reason is that I defined in Strategy other methods that need to be overridden, but not all subclasses (i.e., strategies) need them all. The alternative solution of defining more than one interface and have each strategy implement only the relevant interfaces seemed cumbersome.

No comments:

Post a Comment