StackOverFlow In C# - 在列表中创建列表

StackOverFlow In C# - Lists been created inside lists

最近我对一份工作申请进行了在线测试,结果非常糟糕。

我的挑战是用 C# 创建剪刀石头布游戏(稍后可能添加蜥蜴和史波克)。

我决定创建一个抽象的class选择,所有可能的选择通过多态得到他的行为。

而这个选择 class 有一个空的选择列表,其中包含所有获胜的可能性。像这样:

public class Scissor : Choice
{
    public Scissor()
    {
        Init();
    }

    public override void Init()
    {
        Winners = new List< Choice >();
        Winners.Add(new Paper());
        Winners.Add(new Lizard());
    }        
}

问题是我正在重新创建另一个 Choices 实例(如 Paper 和 Lizard),然后使用自己的获胜者列表,这在我的程序中创建了一个 Whosebug。

我的解决方案是:我自己创建 Scissors class 我 运行 Init() 方法(从构造函数中删除)。我不喜欢这种方法,因为在 "Design Patters" 概述中看起来很糟糕。 (我可以想象其他开发人员创建另一个 class 并忘记调用 Init 方法。

面试官告诉我应该为此使用 Singleton,但我看不出这会有什么帮助。

有人可以为我解释这有什么帮助吗?

你可以采用这样的方法,你可以让游戏 class 单例实例化游戏 class 之后,你可以调用 PlayGame 方法来玩所有选项

  public class Choice
    {
        public virtual void Play()
        {
            Console.WriteLine("Base Choice Played");
        }
    }

    public  class Rock : Choice
    {
        public override void Play() 
        {
            base.Play();
            Console.WriteLine("Rock Played");
        }
    }

    public class Paper : Choice
    {
        public override void Play()
        {
            base.Play();
            Console.WriteLine("Paper Played");
        }
    }

    public class Scissors : Choice
    {
        public override void Play()
        {
            base.Play();
            Console.WriteLine("Scissors Played");
        }
    }

    public class Game
    {
        //You can make this class singleton
        List<Choice> choices = new List<Choice>();
        public Game()
        {
            choices.Add(new Rock());
            choices.Add(new Paper());
            choices.Add(new Scissors());
        }

        public void PlayGame()
        {
            foreach (var choice in choices)
            {
                choice.Play();
            }
        }
    }

这是一个很好的练习,因为如果您想一次性完成所有事情(意味着对象初始化和获胜者设置),您将站在一个有循环引用的地方进行设置。 即: Rock: winner -> Paper: winners -> Scissors: winners -> Rock (所以在这一步你会失败进入一个圆圈,除非你做一些事情来阻止它)

这是我使用单例模式的方法

    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;
        }
    }

您可以看到与您的不同之处在于我为每个选择类型都有一个静态实例,因此您每次尝试为另一个选择设置获胜者时都不会创建一个新实例。

对于我上面提到的循环引用,我添加了一个标志来指示您是否已经为该特定选择输入了设置。因此,当您第二次尝试为特定选择获取实例时,如果您已经处于设置状态,请打破该参考圈。