Search code examples
c#singletonstack-overflow

StackOverFlow In C# - Lists been created inside lists


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 ?


Solution

  • 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.