【问题标题】:How to avoid a switch block with 300 cases?如何避免 300 个 case 的 switch 阻塞?
【发布时间】:2011-09-29 21:08:40
【问题描述】:

我正在尝试将 300 个挑战添加到我的程序中,但仅在 CompletionValue.IsChecked = false 时才显示它们;

如果您正在创建此程序。您将如何存储挑战? 我正在使用开关,但有 300 个案例是多余的,有没有更好的方法?

非常感谢任何关于改进代码的建议。 我对此有些陌生。

    Random rand = new Random();
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        AnswerValue.Visibility = Visibility.Collapsed;
        Load();

    }


    private void Load()
    {
        int random = rand.Next(1, 4);
        switch (random)
        {
            case 1:
                Challenge1();
                break;
            case 2:
                Challenge2();
                break;
            case 3:
                Challenge3();
                break;
        }
    }

    private void Challenge1()
    {
        DifficultyValue.Text = "20%";
        CompletionValue.IsChecked = false;
        TitleValue.Text = "Chicken or Egg?";
        QuestionValue.Text = "Can you answer the ancient question: Which came first the chicken of the egg?";
        bmp.UriSource = new Uri("Images/Challenge1.png", UriKind.Relative);
        ImageValue.Source = bmp;
        ImageValue.Visibility = Visibility.Visible;
        ResourceValue.Text = "Resource: Brain Games";
        AnswerValue.Text = "The Egg. According to paleontologists, reptiles and dinosaurs existed long before birds and chickens.  Fossilized eggs dating back on hundred millions years have been uncovered. Thus it can be said that eggs came before chickens.";

    }

    private void Challenge2()
    {
        DifficultyValue.Text = "25%";
        CompletionValue.IsChecked = false;
        TitleValue.Text = "Halving Seven";
        QuestionValue.Text = "Can you prove that seven is half of twelve?";
        bmp.UriSource = new Uri("Images/Challenge2.png", UriKind.Relative);
        ImageValue.Source = bmp;
        ImageValue.Visibility = Visibility.Visible;
        ResourceValue.Text = "Resource: Yahoo Questions";
        AnswerValue.Text = "Roman numeral for 12 - XII \n Cut the roman numeral in half. you will get VII, which is 7.";

    }

    private void Challenge3()
    {
        DifficultyValue.Text = "25%";
        CompletionValue.IsChecked = false;
        TitleValue.Text = "Three-coin flip";
        QuestionValue.Text = "You ask a friend about probability, and he tells you the following: The odds of three tossed coins turning up all heads or all tails is one in two, that is, fifty-fifty. That’s because anytime you toss three coins, at least two must match, either two heads or two tails.  So that means the third coin—which is equally likely to be heads or tails—determines the odds.” Is your friend right? If not, what are the odds of three tossed coins turning up all heads or all tails?";
        bmp.UriSource = new Uri("Images/Challenge3.png", UriKind.Relative);
        ImageValue.Source = bmp;
        ImageValue.Visibility = Visibility.Visible;
        ResourceValue.Text = "Resource: Brain Games";
        AnswerValue.Text = "Answer will be available soon";
    }

【问题讨论】:

    标签: c# switch-statement maintainability


    【解决方案1】:

    你们的挑战看起来非常相似,对吧?在这种情况下,您希望提取出一个通用数据结构,并将每个挑战表示为一条数据。

    通过统一表示您的挑战,您可以根据特定挑战 ID 的挑战数据设置 UI。

    始终可以将数据移动到 XML 文件、JSON 文件或数据库中,但首先要看看简单的 C# 解决方案是否适合您:

    // Note: This example is simplified for readability
    
    // Here is the common data structure that can represent all challenges
    private class Challenge
    {
        public string Title { get; set; }
        public string Question { get; set; }
        public string ImagePath { get; set; }
    }
    
    // All of the challenges are defined right here, as simple data
    private Challenge[] _allChallenges = new Challenge[]
    {
        new Challenge
        {
            Title = "Chicken or Egg?",
            Question = "Can you answer the ancient question: Which came first the chicken of the egg?",
            ImagePath = "Images/Challenge1.png",
        },
        new Challenge
        {
            Title = "Halving Seven?",
            Question = "Can you prove that seven is half of twelve?",
            ImagePath = "Images/Challenge1.png",
        },
    }
    
    // Choosing challenges is as simple as indexing into the array
    private void Load()
    {
        int random = rand.Next(1, 4);
        Challenge chosenChallenge = _allChallenges[random];
        LoadChallenge(chosenChallenge);
    }
    
    // Setting up the UI for a challenge means extracting information from the data structure
    private void LoadChallenge(Challenge chosenChallenge)
    {
        TitleValue.Text = chosenChallenge.Title;
        QuestionValue.Text = chosenChallenge.Text;
        bmp.UriSource = new Uri(chosenChallenge.ImagePath, UriKind.Relative);
        ImageValue.Source = bmp;
        ImageValue.Visibility = Visibility.Visible;
    }
    

    您可以将其视为declarative programming 的一种形式。程序的一个重要部分,即挑战本身,已从命令式语句(设置 UI 属性)转换为非常简单的数据声明。

    通过进行此转换,您甚至可以检查每个挑战以确保所有部分都已填写。然后,您将确定为您的 300 个挑战中的每一个设置了标题、问题、资源、答案等。

    【讨论】:

      【解决方案2】:

      您可以将挑战保存在数据库或文件中。我确实看到您使用的是随机数并且仅显示 1 个挑战。数据库可以是类似的东西

      ChallengeId, DifficultyValue, TitleValue ... 
      

      ChallengeId 将是 questionId 编号。因此,根据生成的随机数,您可以选择特定的 ChallengeId 和相关数据。

      【讨论】:

      • +1 必须同意这里。编写 300 个挑战似乎是个坏主意。
      【解决方案3】:

      您真正应该研究的是封装和多态代码。通过将您喜欢的属性封装到一个类中,您可以更好地表示“挑战”作为一个整体,并且能够重用您必须一遍又一遍地键入的部分 (.Text = "...") 将使您的未来编码生活无限美好。诚然,即使编写Challenge 实体列表(如下所示)也不好玩,您必须在某个时候输入该数据。我们只是将其视为编码练习,您可以轻松地修改下面的代码以从数据库或序列化文件中填充 _challenges

      public class Challenge
      {
          public int Id {get;set;}
          public int Difficulty {get;set;}
          public bool IsCompleted {get;set;}
          public string Title {get;set;}
          public string Question {get;set;}
          public string Answer {get;set;}
      }
      
      public class MainPage
      {
          private List<Challenge> _challenges;
          private Random rand = new Random();
          public MainPage()
          {
              _challenges = new List<Challenge> {
                  new Challenge {
                          Id = 1,
                          Difficulty = 20,
                          Title = "What came first?",
                          Question =  "The chicken or the egg?",
                          Answer = "The egg." },
                  new Challenge {
                          Id = 2,
                          Difficulty = 30,
                          Title = "Make 7 from 12?",
                          Question =  "Can you prove 7 is half of 12?",
                          Answer = "VII" }};
          }
      
          public void LoadChallenge(Challenge challenge)
          {
              Difficulty.Test = String.Format("%{0}", callenge.Difficulty);
              Completeted.Value = challenge.IsCompleted;
              Title.Test = challenge.Title;
              // etc
          }
      
          public void StartNewChallenge()
          {
              Challenge nextChallenge = null;
              while(nextChallenge == null)
              {
                  var nextId = rand.Next(1,2);
                  nextChallenge = _challenges
                      .Where(x => x.Id == nextId && !x.IsCompleted)
                      .SingleOrDefault(); // default to null if completed == true
              }
              LoadChallenge(nextChallenge);
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        另一种选择可能是某种工厂方法:

        MyForm.cs

        public class MyForm
        {
            Random rand = new Random();
            // Constructor
            public MainPage()
            {
                InitializeComponent();
                AnswerValue.Visibility = Visibility.Collapsed;
                Load();
            }
        
            private void Load()
            {
                int random = rand.Next(1, 4);
                DisplayChallenge(ChallengeFactory.GetChallenge(random));
            }
        
            private void DisplayChallenge(ChallengeFactory.Challenge challengeToDisplay)
            {
                DifficultyValue.Text = String.Format("{0}%", challengeToDisplay.Difficulty);
                CompletionValue.IsChecked = challengeToDisplay.IsChecked;
                TitleValue.Text = challengeToDisplay.Title;
                QuestionValue.Text = challengeToDisplay.Question;
                ImageValue.Source = challengeToDisplay.ImageSource;
                ImageValue.Visibility = challengeToDisplay.Visible;
                ResourceValue.Text = challengeToDisplay.ResourceValue;
                AnswerValue.Text = challengeToDisplay.Answer;
            }
        }
        

        ChallengeFactory.cs

        public static class ChallengeFactory
        {
            public class Challenge
            {
                public int Difficulty { get; set; }
                public bool IsChecked { get; set; }
                public string Title { get; set; }
                public string Question { get; set; }
                public Uri ImageSource { get; set; }
                public bool Visible { get; set; }
                public string ResourceValue { get; set; }
                public string Answer { get; set; }
        
                private Challenge(int difficulty, bool isChecked, string title, string question, Uri imageSource, bool visible, string resourceValue, string answer)
                {
                    // assign each of the arguments to the instance properties
                }
            }
        
            public static Challenge GetChallenge(int challengeNumber)
            {
                switch(challengeNumber)
                {
                    case 1:
                        return new Challenge(20, false, "Chicken or Egg?", "Can you answer the ancient question: Which came first the chicken of the egg?", new Uri("Images/Challenge1.png", UriKind.Relative), true, "Resource: Brain Games", "The Egg...");
                    break;
                    case 2:
                        // new challenge for challenge #2
                    break;
                    case 3:
                        // new challenge for challenge #3
                    break;
                }
            }
        }
        

        请注意,我已将 Challenge 类设为 Factory 类中的嵌套类。 这样做的好处是您可以将挑战的构造函数设为 private(意味着您不能通过工厂方法创建“无效”类型的挑战。这样做的坏处是你必须通过在它的包含类前面加上前缀来进一步限定挑战类,即ChallengeFactory。我认为这是值得的本例中的额外限定符。

        最终,如果您打算在代码中定义所有挑战,我认为您必须创建一个开关SOMEWHERE。正如其他人所说,您可以通过在外部数据源(例如数据库)中定义挑战并使用单一方法来读取、解析和创建一个Challenge 实例。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多