Recently I took a online test for a Job application that went really bad.
My Challenge was to create a Rock-Paper-Scissors Game in C# (with a later possibility to add Lizard and Spock).
I Decided to create a abstract class Choice and all the possibles choices gets his behaviour by polymorphism.
And this Choice class has a empty List of Choices with all the possibilities of winning. Like This:
public class Scissor : Choice
{
public Scissor()
{
Init();
}
public override void Init()
{
Winners = new List< Choice >();
Winners.Add(new Paper());
Winners.Add(new Lizard());
}
}
The problem is that I'm recreating another instances of Choices (like Paper, and Lizard), with then own List of Winners, and this is creating a Stackoverflow in my program.
My solution for that is: I create the Scissors class I run the Init() method by myself (removing from the constructor). I don't like this approach because looks bad in a "Design Patters" overview. (I can image a other developer creating another class and forgetting to call the Init method.
The Interviewer told that I should use Singleton for that, but I fail to see how that would help.
Can somebody explain for me how this would help ?
This is a good exercise because if you want to do everything in one go (meaning object initialization and winners setup) you'll be standing in a place where you have a circular reference when doing setup. i.e: Rock: winner -> Paper: winners -> Scissors: winners -> Rock (so in this step you fail into a circle unless you do something to prevent it)
This is my approach using singleton pattern
public abstract class GameChoice
{
public List<GameChoice> Winners = new List<GameChoice>();
public int Compare(GameChoice other)
{
// Returns -1, 0, 1 depending on result
// -1 - Source choice is beaten.
// 0 - choices match.
// 1 - Source choice wins.
return Winners.Contains(other) ? -1 : other.Winners.Contains(this) ? 1 : 0;
}
}
public class Rock : GameChoice
{
private static Rock instance = null;
private static bool WinnersConfigured = false;
public Rock()
{
if(!WinnersConfigured)
{
WinnersConfigured = true;
Winners.Add(Paper.GetInstance());
}
}
public static Rock GetInstance()
{
if (instance == null)
instance = new Rock();
return instance;
}
}
You can see that the difference with yours is that I have a static instance for each choice type, so you don't create a new instance every time you try to setup the winners for another choice.
And for the circular reference I talked about above, I added a flag to indicate if you already entered the setup for that specific choice. So the second time you try to get an instance for a particular choice, if you're already in setup state, break that reference circle.