Java: Regenerating Nested Loops

I am currently implementing an algorithm that builds a matrix template based on mathematical formulas. For this I use deeply nested for-loops and alto if-conditions in it. The problem is that I cannot break the loop into multiple methods without providing many parameters. And at the moment the code looks like unwanted spaghetti code.

Here's a small pseudo example:

int steps = 10;

void evaluate( int numOuterArea , int numInnerArea , int[] solution , int[] factor , int[] indices )
{
  int counterA = 0;
  int counterB = 0;

  for( int outerAreaIter = 0 ; outerAreaIter < numOuterArea ; outerAreaIter++ )
  {
    for( int curOuterAreaIter = 0 ; curOuterAreaIter < steps ; curOuterAreaIter++ )
    {
      for( int innerAreaIter = 0 ; innerAreaIter < numInnerArea ; innerAreaIter++ )
      {
        for( int curInnerAreaIter = 0 ; curInnerAreaIter < curOuterAreaIter ; curInnerAreaIter++ )
        {
          if( curInnerAreaIter == curOuterAreaIter )
          {
            // do something with solution, factor or indices
          }
          else if( /* some other fancy condition */)
          {

          }
          ...
        }
      }
    }
  }

  // similar nested loops follow here
}

      

If I were to write classes / methods for each loop or part of the loop, I have to provide all the parameters from evaluate()

(which could be even more, as shown in the example) as well as all previous iterators and possible variables.

Is there a way / common practice / any hints or tips to better rewrite code like this?

+3


source to share


2 answers


The easiest way is to encapsulate all parameters in one object. You can use this object to pass data as the only parameter to the evaluation method. Something like this example:



class EvaluationContext {
    int numOuterArea;
    int numInnerArea;
    int[] solution;
    int[] factor;
    int[] indices;
}

interface Evaluator {
    void evaluate(EvaluationContext ctx); 
}

class FirstEvaluator implements Evaluator {
    void evaluate(EvaluationContext ctx) {
        SecondEvaluator e2 = new SecondEvaluator(); 
        for (...) {
            e2.evaluate(ctx);
        }
    }
}

class SecondEvaluator implements Evaluator {
    void evaluate(EvaluationContext ctx) {
        // evaluate something and put result into context
    }
}

      

+2


source


A simple design pattern is Method Object . Just write a class that is responsible for this calculation. Then you might have fields that simply store intermediate results during this calculation. With this approach, you don't need to pass any arguments.

Example:



class EvaluateMethod {
    private final int numOuterArea;
    private final int numInnerArea;
    private final int[] solution;
    private final int[] factor;
    private final int[] indices;

    // place fields for intermediate results here

    EvaluateMethod(int numOuterArea, int numInnerArea, int[] solution, int[] factor, int[] indices) {
        // assign all parameter to fields here
    }

    void execute() {
        // Your method body as before comes here.
        // But you can extract methods easily.
    }
}

      

One more note: you cannot reuse an instance of this class. I call them one shot objects that need to be created, used and discarded.

+1


source







All Articles