【问题标题】:Modifying type hierarchies at runtime在运行时修改类型层次结构
【发布时间】:2014-12-26 13:14:39
【问题描述】:

我什至无法定义我在寻找什么。

我正在编写一个应用程序来确定锦标赛的获胜者。我希望我的基类能够根据玩游戏的人数来改变它的继承,因为多重继承不是一种选择,而且我越想它可能就不是一个很好的选择。

我看到了一些类似的东西

class Base
{
   //Constructor receiving the quantity of players
   public Base (int quantityOfPlayers)
   {
      //Changes Base inheritance dynamically based on QuantityOfPlayers
      switch (quantityOfPlayers)
      {
         case 4: (Base : FourPlayers);
         case 5: (Base : FivePlayers);
      }
   }
}

当然,我似乎无法找到一种方法(如果有的话)像这样动态地改变继承。否则我会使用更复杂的方法,尽管每个 getter 和 setter 函数都将基本相同。


非常好的解决方案。让我补充一下,我使用的是 GUI 而不是控制台。

我必须考虑一下,工厂课程很好,但它让我确信我在考虑我的方法。

【问题讨论】:

  • 根据玩家数量更改继承听起来不太好Software Design。也许如果您详细说明为什么需要根据玩家数量更改继承,我们可以提出解决此问题的不同最佳方法。
  • @OrelEraki 通常会同意,但对于游戏来说,看看这对于菜单导航之类的东西如何非常有用
  • @Franky_D 我的回答细节看起来很复杂,因为我在一个领域提供了一个完整的示例,基本上你将拥有你的基本功能,在接口和基类中定义合同,如果你想覆盖一个您使用的合同的特定元素IContractName.MethodName 语法

标签: c# multiple-inheritance


【解决方案1】:

针对这种情况,有一种叫做strategy pattern的软件设计模式。

为游戏策略定义一个界面

public interface IGameStrategy
{
    // Things that depend on the number of players, go here...
}

通过constructor injection将正确的策略注入游戏

public class Game
{
    private IGameStrategy _strategy;

    // Constructor injection
    public Game(IGameStrategy strategy)
    {
        _strategy = strategy;
    }

    // Things common to all types of games go here...
}

像这样定义一个factory 方法:

private IGameStrategy CreateGameStrategy(int numberOfPlayers)
    switch (numberOfPlayers)
    {
        case 4:
            return FourPlayersStrategy();
        case 5:
            return FivePlayersStrategy();
        default:
            throw new ArgumentException("Invalid number of players");
    }
}

然后像这样创建一个游戏:

var game = new Game(CreateGameStrategy(numberOfPlayers));

当然,策略类实现了接口。他们可以直接这样做,也可以继承实现接口的通用抽象基类。

游戏逻辑分为在 Game 类中实现的所有类型的游戏共有的部分,以及在策略类中实现的特定于玩家数量的部分。

【讨论】:

    【解决方案2】:

    您可以创建一个工厂类,根据玩家数量生成适当的类:

    public class PlayerQtyFactory
    {
        //You can add any other args you might need as well
        public BaseClass CreatePlayerQty(int numPlayers)
        {
    
          switch (numPlayers)
          {
              Case 2:
                return new TwoPlayers();
    
              Case 3:
                return new ThreePlayers();
    
          {
        }
    }
    

    如果不了解您正在尝试做什么,很难说这是否是最好的方法,但它肯定是一种方法。

    【讨论】:

      【解决方案3】:

      对于这种特殊情况,我会使用工厂式(或只是计划工厂)解决方案

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace Tester
      {
          //declare common functionality
              public interface ISharedFunctionality 
              {
                  //put all shared functionality here
                  void SomeMethod();
                  void SomeOtherMethod();
      
                  void DifferentMethod();
                  string Name {get;set;}
              }
      
              public interface ISinglePlayerFunctionality : ISharedFunctionality
              {
                  //put single player functionality here
                  void SomeOtherMethod();
                  void SomeMethod();
              }
      
              public interface IMultiplePlayerFunctionality : ISharedFunctionality
              {
                  //put multiplayer functionality here
                  void DifferentMethod();
                  void SomeMethod();
              }
      
              public class ImplementationBase : ISharedFunctionality
              {
                  //shared implementation here
                  public void SomeMethod()
                  {
                      //do stuff
                      Console.WriteLine("In Base");
                  }
                  public void SomeOtherMethod()
                  {
                      //one you don't want to inherit in multiplayer
                      Console.WriteLine("In Base");
                  }
                  public void DifferentMethod() 
                  {
                      Console.WriteLine("In Base");
                  }
      
      
                  public string Name
                  {
                      get;
                      set;
                  }
      
      
              }
      
              public class MultiPlayerImplementation : ImplementationBase, IMultiplePlayerFunctionality
              {
                  //multiplay impl
                  // you inherit some method but don't want to inherit 
                  //SomeOtherMethod when cast to ISharedFunctionality
                  void ISharedFunctionality.SomeMethod()
                  {
                      //when cast to ISharedFunctionality this method will execute not inherited
                      Console.WriteLine("In MutilPlayImplementation");
                  } 
              }
      
              public class SinglePlayerImplementation : ImplementationBase , ISinglePlayerFunctionality
              {
                  //singleplay impl
      
                  void ISharedFunctionality.SomeOtherMethod()
                  {
                      Console.WriteLine("In SinglePlayerImplementation" );
                  }
      
      
              }
      
              public class Factory 
              {
                  //logic to decide impl here
                  public ISharedFunctionality Create(int numberOfPlayer)
                  {
                      if (numberOfPlayer == 1)
                      {
                          return new SinglePlayerImplementation();
                      }
                      else if(numberOfPlayer > 1)
                      {
                          return new MultiPlayerImplementation();
                      }
      
                      return null;
                  }
              }
      
          class Program
          {
              static void Main(string[] args)
              {
      
                  var factory = new Factory();
                  var results = new[]{factory.Create(1) , factory.Create(2) };
      
                  int j=0;
                  foreach (var i in results) 
                  {
                      ///for single player will be base
                      ///multiplaryer will be mutliplayer
                      i.SomeMethod();
                      //for single player will be single player
                      // for multiplayer will be base
                      i.SomeOtherMethod();
                      i.DifferentMethod();
                      i.Name = "Item-Number-" + j;
                      Console.WriteLine();
                  }
      
              }
          }
      }
      

      这样做的好处是双重的,您现在在调用什么方法方面不再有歧义,并且您有一个统一的地方来构建基于类似合同的未来实现(即三个玩家行为,不同的菜单行为,如果您希望完全相同的方法表现不同,则可能需要更少的代码

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-14
        • 2013-03-20
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多