【问题标题】:Design pattern for classes with certain constraint具有特定约束的类的设计模式
【发布时间】:2014-09-30 13:39:02
【问题描述】:

我最近在一次采访中被问到这个问题。我必须为板球比赛设计课程,其中将有针对团队、球员等的课程。一个板球队只能有 11 名球员。我必须设计课程,使团队可以有一个限制,即它只能拥有一定数量的某种类型的球员。例如,一个限制条件是一支球队只能有 4 名击球手、5 名投球手和 2 名全能球员。或者,一支球队可以有 3 名击球手、6 名投球手和 2 名全能球员的限制。

那么对于这种场景是否有特定的设计模式?

【问题讨论】:

    标签: object design-patterns class-design


    【解决方案1】:

    没有。

    总结起来(来自下面的 cmets)您最多可以有 11 名玩家。这就是约束。

    我可以通过在构造函数中获取两种玩家的数量作为参数来轻松解决这个问题——例如Team::Team(int batsmen, int bowlers)——然后计算另一个数字作为差异:

    class Team {
    
    public:
    
    Team::Team (int batsmen, int bowlers){
        if (batsmen + bowlers > 14) 
             throw std::runtime_error ("Too many players");
        int rounders = 14 - batsmen - bowlers;        
        // Allocate players
    }
    
    private:
        std::vector<Batsman> bat_;
        std::vector<Bowler> bows_;
        std::vector<Rounder> rounds_;
    };
    

    【讨论】:

    • 一支球队可以拥有的击球手、投球手或全能球员的数量不是固定的。这就是约束。
    • 如果我错了,请纠正我,但首先你说“球队可以有一个限制,它只能有 一定数量 类型的球员”,然后是“一支球队可以拥有的击球手、投球手或全能球员的数量不固定。这就是限制。”哪个是真实的?
    • 所以,你的问题根本不清楚。您甚至可以在运行时将数字作为 Team::Team() 构造函数的参数。例如,Team::Team(int batsmen, int bowlers, int rounders)。然后,在 Team 构造函数中,分配新的所需参数的数量。
    • 很抱歉给您带来了困惑。我已经更新了问题陈述。
    • 所以,如果我理解的很好的话,约束是各种玩家的总和。对吗?
    【解决方案2】:

    要真正说出任何有意义的事情,我需要更多关于游戏和未来的信息。

    我只能猜测问题的目标是什么。在某一时刻,他们可能会问“如果限制条件是击球手的体重不应超过 80 公斤怎么办?)

    类似的东西:

    void Main()
    {
        Console.WriteLine("Current team valid: " +
            new Team(
                new List<Player>{
                    new Batsmen(),
                    new Batsmen(),
                    new Batsmen(),
                    new Batsmen()
                }).IsTeamValid());
    }
    
    abstract class Player {}
    class Batsmen : Player{}
    
    class Team {
        static readonly IList<TeamConstraint> DefaultConstraints 
            = new List<TeamConstraint>{new BatsmenConstraint()};
    
        IList<TeamConstraint> _constraints;
        IList<Player> _players;
    
        public Team(IList<Player> players) : this(players, DefaultConstraints){}
        public Team(IList<Player> players, IList<TeamConstraint> constraints){
            _constraints = constraints;
            _players = players;
        }
    
        public bool IsTeamValid(){
            return _constraints.All(constraint => constraint.IsValid(_players));
        }
    }
    
    abstract class TeamConstraint
    {
        public abstract bool IsValid(IList<Player> players);
    }
    
    class BatsmenConstraint : TeamConstraint
    {
        const int batsmenRequiredDefault = 4;
        readonly int _batsmenRequired;
    
        public BatsmenConstraint(int batsmenRequired = batsmenRequiredDefault){
            _batsmenRequired = batsmenRequired;
        }
    
        public override bool IsValid(IList<Player> players){
            return players.OfType<Batsmen>().Count() == _batsmenRequired;
        }
    }
    

    如您所见,约束与 Team 类是分开的。这样,您将遵循 SOLID 原则。

    你可以:

    1) 动态添加新的团队配置

    2) 在不修改现有系统的情况下动态创建新约束。

    至于你的问题;没有“板球比赛设计模式”。尝试解决此问题时,您可以使用几种不同的模式,其中一种模式比其他模式更适合问题,等等。

    我在这里所做的基本上是使用“bridge pattern”来

    将抽象与其实现解耦,这样两者就可以 独立变化。

    谈到 Team 和 TeamConstraint 之间的关系时。

    【讨论】:

      【解决方案3】:

      这与特定的设计模式无关。

      我认为这样一个问题(尤其是在面试中)的意义在于你充实了各种设计选项。例如,让我们从

      class AbstractPlayer
      { /* stuff */ };
      
      class Batsman : public AbstractPlayer
      { /* stuff */ };
      
      class Bowler : public AbstractPlayer
      { /* stuff */ };
      
      class AllRounder : public AbstractPlayer
      { /* stuff */ };
      

      那你可以去

      class Team
      {
      public:
          void addPlayer(Batsman player);
          void addPlayer(Bowler player);
          void addPlayer(AllRounder player);
      
          /* stuff */ 
      };
      

      也可以是

      class Team
      {
      public:
          void addBatsman(AbstractPlayer player);
          void addBowler(AbstractPlayer player);
          void addAllRounder(AbstractPlayer player);
      
          /* stuff */ 
      };
      

      无论如何,你必须决定是否

      1. 将这些玩家存储在一个AbstractPlayers 列表中,并计算不同整数属性中不同玩家类型的数量或
      2. 将播放器存储在三个不同的动态长度列表中

      到目前为止一切顺利,现在假设您以某种方式拥有Team 类中的玩家类型数量。约束在哪里?它们可以在构造函数中设置为三个最大计数

      Team::Team(int maxBatsmanCount, int maxBowlerCount, int maxAllRounderCount) { ... }
      

      或者可能有某种 setter 方法(如果对于一个 Team 实例,数字可能会改变)

      Team::adjustConstraints(int maxBatsmanCount, int maxBowlerCount, int maxAllRounderCount) { ... }
      

      还有更多我能想到的方法。约束类怎么样?但这取决于Team 类的要求。

      【讨论】:

      • 你能详细说明你的最后一行吗?
      【解决方案4】:

      您可以使用简单的Specification 模式:

      class MyTeamPlayersSpecification {
      
        bool isSatisfiedBy(Team team) {
          // return team.batsmenCount == 4 && ...
        }
      }
      

      每次添加玩家时是否在团队构建时或在 Validate() 方法中验证规范取决于问题上下文和您的个人偏好。

      【讨论】:

        【解决方案5】:
        class TeamFactory
        {
            static const int bowler;
            static const int batsman;
            static const int allrounder;
            static const int totalPlayer;
        
            static Team* getTeam(int _bowler, int _batsman, int _allrounder)
            {
                if (((_bowler + _batsman + _allrounder) > totalPlayer) ||   (allrounder condition) || (_batsman condition) || _allrounder condition)
                {
                    //  error msg
                    getTeam( _bowler, _batsman, _allrounder)
                }
                else
                {
                     // create instance,
                }
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 2011-05-12
          • 1970-01-01
          • 2019-03-04
          • 1970-01-01
          • 2011-08-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-21
          相关资源
          最近更新 更多