2013-07-22 4 views
0

Я начал рефакторинг этой программы, над которой я работал, и попал в главный дорожный блок ... У меня есть один класс, который действует как ядро, с примерно 6 другими меньшими (но все же важными) классами работая вместе, чтобы запустить программу ... Я взял один метод [называемый «populate()») из класса ядра и сделал с ним совершенно новый класс [называемый «PopulationGenerator»], но когда я пытаюсь создать объект вновь созданный класс где-нибудь в классе ядра я застрять в бесконечном цикле этого нового классане могу найти источник непреднамеренного цикла

никогда я не имел эту проблему при попытке создать объекты, прежде чем ... Вот класс ядра до рефакторинга:

public class Simulator 
{ 
    // Constants representing configuration information for the simulation. 
    // The default width for the grid. 
    private static final int DEFAULT_WIDTH = 120; 
    // The default depth of the grid. 
    private static final int DEFAULT_DEPTH = 80; 
    // The probability that a fox will be created in any given grid position. 
    private static final double FOX_CREATION_PROBABILITY = 0.02; 
    // The probability that a rabbit will be created in any given grid position. 
    private static final double RABBIT_CREATION_PROBABILITY = 0.08;  

    // List of animals in the field. 
    private List<Animal> animals; 
    // The current state of the field. 
    private Field field; 
    // The current step of the simulation. 
    private int step; 
    // A graphical view of the simulation. 
    private SimulatorView view; 

    /** 
    * Construct a simulation field with default size. 
    */ 
    public Simulator() 
    { 
     this(DEFAULT_DEPTH, DEFAULT_WIDTH); 
    } 

    /** 
    * Create a simulation field with the given size. 
    * @param depth Depth of the field. Must be greater than zero. 
    * @param width Width of the field. Must be greater than zero. 
    */ 
    public Simulator(int depth, int width) 
    { 
     if(width <= 0 || depth <= 0) { 
      System.out.println("The dimensions must be greater than zero."); 
      System.out.println("Using default values."); 
      depth = DEFAULT_DEPTH; 
      width = DEFAULT_WIDTH; 
     } 

     animals = new ArrayList<Animal>(); 
     field = new Field(depth, width); 

     // Create a view of the state of each location in the field. 
     view = new SimulatorView(depth, width); 
     view.setColor(Rabbit.class, Color.orange); 
     view.setColor(Fox.class, Color.blue); 

     // Setup a valid starting point. 
     reset(); 
    } 

    /** 
    * Run the simulation from its current state for a reasonably long period, 
    * (4000 steps). 
    */ 
    public void runLongSimulation() 
    { 
     simulate(4000); 
    } 

    /** 
    * Run the simulation from its current state for the given number of steps. 
    * Stop before the given number of steps if it ceases to be viable. 
    * @param numSteps The number of steps to run for. 
    */ 
    public void simulate(int numSteps) 
    { 
     for(int step = 1; step <= numSteps && view.isViable(field); step++) { 
      simulateOneStep(); 
     } 
    } 

    /** 
    * Run the simulation from its current state for a single step. 
    * Iterate over the whole field updating the state of each 
    * fox and rabbit. 
    */ 
    public void simulateOneStep() 
    { 
     step++; 

     // Provide space for newborn animals. 
     List<Animal> newAnimals = new ArrayList<Animal>();   
     // Let all rabbits act. 
     for(Iterator<Animal> it = animals.iterator(); it.hasNext();) { 
      Animal animal = it.next(); 
      animal.act(newAnimals); 
      if(! animal.isAlive()) { 
       it.remove(); 
      } 
     } 

     // Add the newly born foxes and rabbits to the main lists. 
     animals.addAll(newAnimals); 

     view.showStatus(step, field); 
    } 

    /** 
    * Reset the simulation to a starting position. 
    */ 
    public void reset() 
    { 
     step = 0; 
     animals.clear(); 
     populate(); 

     // Show the starting state in the view. 
     view.showStatus(step, field); 
    } 

    /** 
    * Randomly populate the field with foxes and rabbits. 
    */ 
    private void populate() 
    { 
     Random rand = Randomizer.getRandom(); 
     field.clear(); 
     for(int row = 0; row < field.getDepth(); row++) { 
      for(int col = 0; col < field.getWidth(); col++) { 
       if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) { 
        Location location = new Location(row, col); 
        Fox fox = new Fox(true, field, location); 
        animals.add(fox); 
       } 
       else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) { 
        Location location = new Location(row, col); 
        Rabbit rabbit = new Rabbit(true, field, location); 
        animals.add(rabbit); 
       } 
       // else leave the location empty. 
      } 
     } 
    } 
} 

EDIT:

Вот этот же класс после рефакторинга ...

import java.util.Random; 
import java.util.List; 
import java.util.ArrayList; 
import java.util.Iterator; 
import java.awt.Color; 

/** 
* A simple predator-prey simulator, based on a rectangular field 
* containing rabbits and foxes. 
* 
* Update 10.40: 
* Now *almost* decoupled from the concrete animal classes. 
* 
* @TWiSTED_CRYSTALS 
*/ 
public class Simulator 
{ 
    // Constants representing configuration information for the simulation. 
    // The default width for the grid. 
    private static final int DEFAULT_WIDTH = 120; 
    // The default depth of the grid. 
    private static final int DEFAULT_DEPTH = 80; 

    // The current state of the field. 
    private Field field; 
    // The current step of the simulation. 
    private int step; 
    // A graphical view of the simulation. 
    private SimulatorView view; 
    //Population Generator class... coupled to fox and rabbit classes 
    private PopulationGenerator popGenerator; 
    // Lists of animals in the field. Separate lists are kept for ease of iteration. 
    private List<Animal> animals; 

    /** 
    * Construct a simulation field with default size. 
    */ 
    public Simulator() 
    {  
     this(DEFAULT_DEPTH, DEFAULT_WIDTH); 

    } 

    /** 
    * Create a simulation field with the given size. 
    * @param depth Depth of the field. Must be greater than zero. 
    * @param width Width of the field. Must be greater than zero. 
    */ 
    public Simulator(int depth, int width) 
    { 

     if(width <= 0 || depth <= 0) { 
      System.out.println("The dimensions must be greater than zero."); 
      System.out.println("Using default values."); 
      depth = DEFAULT_DEPTH; 
      width = DEFAULT_WIDTH; 
     } 

     animals = new ArrayList<Animal>(); 
     field = new Field(depth, width); 

     // Create a view of the state of each location in the field. 
     // 
     //   view.setColor(Rabbit.class, Color.orange); // PG 
     //   view.setColor(Fox.class, Color.blue); // PG 

     // Setup a valid starting point. 
     reset(); 
    } 

    /** 
    * Run the simulation from its current state for a reasonably long period, 
    * (4000 steps). 
    */ 
    public void runLongSimulation() 
    { 
     simulate(4000); 

    } 

    /** 
    * Run the simulation from its current state for the given number of steps. 
    * Stop before the given number of steps if it ceases to be viable. 
    * @param numSteps The number of steps to run for. 
    */ 
    public void simulate(int numSteps) 
    { 
     for(int step = 1; step <= numSteps && view.isViable(field); step++) { 
      simulateOneStep(); 
     } 
    } 

    /** 
    * Run the simulation from its current state for a single step. 
    * Iterate over the whole field updating the state of each 
    * fox and rabbit. 
    */ 
    public void simulateOneStep() 
    { 
     step++; 

     // Provide space for animals. 
     List<Animal> newAnimals = new ArrayList<Animal>();   
     // Let all animals act. 
     for(Iterator<Animal> it = animals.iterator(); it.hasNext();) { 
      Animal animal = it.next(); 
      animal.act(newAnimals); 
      if(! animal.isAlive()) { 
       it.remove(); 
      } 
     } 

     animals.addAll(newAnimals); 

    } 

    /** 
    * Reset the simulation to a starting position. 
    */ 
    public void reset() 
    { 
     PopulationGenerator popGenerator = new PopulationGenerator(); 

     step = 0; 

     animals.clear(); 

     popGenerator.populate(); 

     // Show the starting state in the view. 
     view.showStatus(step, field); 
    } 

    public int getStep() 
    { 
     return step; 
    } 

} 

... и новый класс

import java.util.ArrayList; 
import java.util.Random; 
import java.util.List; 
import java.awt.Color; 

public class PopulationGenerator 
{ 
    // The default width for the grid. 
    private static final int DEFAULT_WIDTH = 120; 
    // The default depth of the grid. 
    private static final int DEFAULT_DEPTH = 80; 

    // The probability that a fox will be created in any given grid position. 
    private static final double FOX_CREATION_PROBABILITY = 0.02; 
    // The probability that a rabbit will be created in any given grid position. 
    private static final double RABBIT_CREATION_PROBABILITY = 0.08; 

    // Lists of animals in the field. Separate lists are kept for ease of iteration. 
    private List<Animal> animals; 
    // The current state of the field. 
    private Field field; 
    // A graphical view of the simulation. 
    private SimulatorView view; 

    /** 
    * Constructor 
    */ 
    public PopulationGenerator() 
    { 
     animals = new ArrayList<Animal>(); 

     field = new Field(DEFAULT_DEPTH, DEFAULT_WIDTH); 

    } 

    /** 
    * Randomly populate the field with foxes and rabbits. 
    */ 
    public void populate() 
    { 
     // Create a view of the state of each location in the field. 
     view = new SimulatorView(DEFAULT_DEPTH, DEFAULT_WIDTH); 

     view.setColor(Rabbit.class, Color.orange); // PG 
     view.setColor(Fox.class, Color.blue); // PG 

     Simulator simulator = new Simulator(); 
     Random rand = Randomizer.getRandom(); 
     field.clear(); 
     for(int row = 0; row < field.getDepth(); row++) { 
      for(int col = 0; col < field.getWidth(); col++) { 
       if(rand.nextDouble() <= FOX_CREATION_PROBABILITY) { 
        Location location = new Location(row, col); 
        Fox fox = new Fox(true, field, location); 
        animals.add(fox); 
       } 
       else if(rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) { 
        Location location = new Location(row, col); 
        Rabbit rabbit = new Rabbit(true, field, location); 
        animals.add(rabbit); 
       } 
       // else leave the location empty. 
      } 
     } 
     view.showStatus(simulator.getStep(), field); 
    } 
} 

вот класс поле, что PopulationGenerator звонки ... Я не изменил этот класс каким-либо образом

import java.util.Collections; 
import java.util.Iterator; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Random; 

/** 
* Represent a rectangular grid of field positions. 
* Each position is able to store a single animal. 
* 
* @TWiSTED_CRYSTALS 
*/ 
public class Field 
{ 
    // A random number generator for providing random locations. 
    private static final Random rand = Randomizer.getRandom(); 

    // The depth and width of the field. 
    private int depth, width; 
    // Storage for the animals. 
    private Object[][] field; 

    /** 
    * Represent a field of the given dimensions. 
    * @param depth The depth of the field. 
    * @param width The width of the field. 
    */ 
    public Field(int depth, int width) 
    { 
     this.depth = depth; 
     this.width = width; 
     field = new Object[depth][width]; 
    } 

    /** 
    * Empty the field. 
    */ 
    public void clear() 
    { 
     for(int row = 0; row < depth; row++) { 
      for(int col = 0; col < width; col++) { 
       field[row][col] = null; 
      } 
     } 
    } 

    /** 
    * Clear the given location. 
    * @param location The location to clear. 
    */ 
    public void clear(Location location) 
    { 
     field[location.getRow()][location.getCol()] = null; 
    } 

    /** 
    * Place an animal at the given location. 
    * If there is already an animal at the location it will 
    * be lost. 
    * @param animal The animal to be placed. 
    * @param row Row coordinate of the location. 
    * @param col Column coordinate of the location. 
    */ 
    public void place(Object animal, int row, int col) 
    { 
     place(animal, new Location(row, col)); 
    } 

    /** 
    * Place an animal at the given location. 
    * If there is already an animal at the location it will 
    * be lost. 
    * @param animal The animal to be placed. 
    * @param location Where to place the animal. 
    */ 
    public void place(Object animal, Location location) 
    { 
     field[location.getRow()][location.getCol()] = animal; 
    } 

    /** 
    * Return the animal at the given location, if any. 
    * @param location Where in the field. 
    * @return The animal at the given location, or null if there is none. 
    */ 
    public Object getObjectAt(Location location) 
    { 
     return getObjectAt(location.getRow(), location.getCol()); 
    } 

    /** 
    * Return the animal at the given location, if any. 
    * @param row The desired row. 
    * @param col The desired column. 
    * @return The animal at the given location, or null if there is none. 
    */ 
    public Object getObjectAt(int row, int col) 
    { 
     return field[row][col]; 
    } 

    /** 
    * Generate a random location that is adjacent to the 
    * given location, or is the same location. 
    * The returned location will be within the valid bounds 
    * of the field. 
    * @param location The location from which to generate an adjacency. 
    * @return A valid location within the grid area. 
    */ 
    public Location randomAdjacentLocation(Location location) 
    { 
     List<Location> adjacent = adjacentLocations(location); 
     return adjacent.get(0); 
    } 

    /** 
    * Get a shuffled list of the free adjacent locations. 
    * @param location Get locations adjacent to this. 
    * @return A list of free adjacent locations. 
    */ 
    public List<Location> getFreeAdjacentLocations(Location location) 
    { 
     List<Location> free = new LinkedList<Location>(); 
     List<Location> adjacent = adjacentLocations(location); 
     for(Location next : adjacent) { 
      if(getObjectAt(next) == null) { 
       free.add(next); 
      } 
     } 
     return free; 
    } 

    /** 
    * Try to find a free location that is adjacent to the 
    * given location. If there is none, return null. 
    * The returned location will be within the valid bounds 
    * of the field. 
    * @param location The location from which to generate an adjacency. 
    * @return A valid location within the grid area. 
    */ 
    public Location freeAdjacentLocation(Location location) 
    { 
     // The available free ones. 
     List<Location> free = getFreeAdjacentLocations(location); 
     if(free.size() > 0) { 
      return free.get(0); 
     } 
     else { 
      return null; 
     } 
    } 

    /** 
    * Return a shuffled list of locations adjacent to the given one. 
    * The list will not include the location itself. 
    * All locations will lie within the grid. 
    * @param location The location from which to generate adjacencies. 
    * @return A list of locations adjacent to that given. 
    */ 
    public List<Location> adjacentLocations(Location location) 
    { 
     assert location != null : "Null location passed to adjacentLocations"; 
     // The list of locations to be returned. 
     List<Location> locations = new LinkedList<Location>(); 
     if(location != null) { 
      int row = location.getRow(); 
      int col = location.getCol(); 
      for(int roffset = -1; roffset <= 1; roffset++) { 
       int nextRow = row + roffset; 
       if(nextRow >= 0 && nextRow < depth) { 
        for(int coffset = -1; coffset <= 1; coffset++) { 
         int nextCol = col + coffset; 
         // Exclude invalid locations and the original location. 
         if(nextCol >= 0 && nextCol < width && (roffset != 0 || coffset != 0)) { 
          locations.add(new Location(nextRow, nextCol)); 
         } 
        } 
       } 
      } 

      // Shuffle the list. Several other methods rely on the list 
      // being in a random order. 
      Collections.shuffle(locations, rand); 
     } 
     return locations; 
    } 

    /** 
    * Return the depth of the field. 
    * @return The depth of the field. 
    */ 
    public int getDepth() 
    { 
     return depth; 
    } 

    /** 
    * Return the width of the field. 
    * @return The width of the field. 
    */ 
    public int getWidth() 
    { 
     return width; 
    } 
} 
+0

Сначала необходимо изолировать, где проблема, прежде чем прийти сюда демпинг код, который не может иметь никакого отношения к этой проблеме вообще. Для изоляции используйте либо отладчик, либо println. Или, если вы уверены, что проблема заключается в этом коде, расскажите нам, почему вы думаете об этом и где в приведенной выше ошибке кода проблема находится. –

+0

Почему ваш новый класс не включен? Я не могу видеть никаких циклов в этом коде, которые могут стать бесконечными, поэтому, возможно, проблема в этом. –

+0

@Mark: Я знаю. Прямо сейчас мы как бы вынуждены угадывать, что происходит в коде, он не показывает нам, что немного расстраивает. На исходном плакате: опять же, ваша ответственность будет заключаться в выполнении некоторых основных шагов отладки, чтобы попытаться изолировать проблему, а затем опубликовать ** этот ** код здесь. –

ответ

0

Ваша проблема не в классе Field, а ниже. Конструктор Simulator вызывает reset(), который создает новый объект PopulationGenerator, а затем вызывает populate() на этом объекте. Метод populate() вызывает Simulator simulator = new Simulator(); который создает новый объект Simulator, который продолжает цикл. Решение: не создавайте новый объект Simulator в PopulationGenerator, а вместо этого передавайте существующий симулятор PopulationGenerator через его конструктор или через метод setSimulator (...).

например,

class PopulationGenerator { 
    // ... etc... 
    private Simulator simulator; // null to begin with 

    // pass Simulator instance into constructor. 
    // Probably will need to do the same with SimulatorView 
    public PopulationGenerator(Simulator simulator, int depth, int width) { 
    this.simulator = simulator; // set the instance 

    // ... more code etc... 

    } 

    public void populate() { 
    // don't re-create Simulator here but rather use the instance passed in 
    } 

} 
+0

ладно, я дам, что выстрел ... у меня еще не было возможности попробовать это, но я не знаю, как это происходит ... спасибо снова, человек –

Смежные вопросы