Declaring a variable inside an `if` statement in J

2019-05-03 02:30发布

问题:

I know, I know, there's a ton of simple answers that cover most cases for how to avoid this.

In my case, I want to use user-input info to create CPU players in a game. If the user chooses easy mode, then I want to declare and instantiate an instance of the EasyPlayer class. Otherwise, I want to declare and instantiate an instance of the HardPlayer class. Either way, the specific name of the variable needs to be "cpu" and the rest of the code operates on "cpu" indiscriminately. That is, all the differences in how these operate are built into their different classes, which subclass the CpuPlayer class.

So here's the code:

// Set the opponent.
if (difficulty == 0){
    EasyPlayer cpu = new EasyPlayer(num_rounds);
}
else{
    HardPlayer cpu = new HardPlayer(num_rounds);
}

This gives me the ever-annoying cannot find symbol error. From what I can read, everyone says you cannot make declarations inside a conditional like this due to scope problems and the possibility that it never occurs.

If so, what is the right way to alternatively declare a single variable as one of either of two different classes based on user input?

回答1:

CpuPlayer cpu;

if (difficulty == 0){
    cpu = new EasyPlayer(num_rounds);
}
else{
    cpu = new HardPlayer(num_rounds);
}


回答2:

If your intention is to call only methods available to the CpuPlayer class, then perhaps a better design pattern to use is the Strategy Pattern. In your case, you would probably add a new class called CpuStrategy, and modify your CpuPlayer constructor to something like:

public CpuPlayer(CpuStrategy strategy, int num_rounds)

This makes the rest of your code easier to read and probably easier to maintain too. Here's what your original snippet of code would look like:

CpuPlayer cpu = new CpuPlayer(new CpuStrategy(difficulty), num_rounds);

We got rid of the if/else since the CpuStrategy class will handle the difference between difficulty levels. This also makes sense since you can abstract away the notion of "difficulty levels" from the meat of your program, which I assume is the game playing part.



回答3:

CpuPlayer cpu; 
// Set the opponent.
if (difficulty == 0){
    cpu = new EasyPlayer(num_rounds);
} else{
    cpu = new HardPlayer(num_rounds);
}


回答4:

Declare it first, and then assign it.

// Set the opponent.
CpuPlayer cpu = null;
if (difficulty == 0){
    cpu = new EasyPlayer(num_rounds);
}
else{
    cpu = new HardPlayer(num_rounds);
}
if(cpu == null) throw new IllegalStateException();


回答5:

// Set the opponent.
CpuPlayer cpu;
if (difficulty == 0){
    cpu = new EasyPlayer(num_rounds);
} else{
    cpu = new HardPlayer(num_rounds);
}


回答6:

You could tweak the design of your class structure. Make a parent class named Level and extend two child classes named EasyLevel and HardLevel.

class EasyLevel : public Level 
{

  //implementation specific to easy level
}

class HardLevel : public Level 
{
  //implementation specific to hard level
}

in your player class, add a modify the constructor to take a parameter of type Level.

class Player
{
  Level level;
  int rounds;

  public:
    Player (Level level, int num_rounds)
    {
       this.level = level;
       this.rounds = num_rounds;
    }

    play ()
    {
       // use level variable to invoke implementation specific to the set level, hard or easy. 
    }
}

This will make you class structure more extendable. As an example if you need to add another Level 'medium' in future, just need to extend from the parent class Level.



回答7:

CpuPlayer cpu = difficulty == 0
    ? new EasyPlayer(num_rounds)
    : new HardPlayer(num_rounds);

cpu can be made final if possible too.