简体   繁体   中英

Design pattern for classes with certain constraint

I was recently asked this question in an interview. I had to design classes for Cricket game where there will be a class for team, for player and so on. There can only be 11 players in a Cricket team. I had to design the classes such that the team can have a constraint that it can have only have certain number of players of a type. For example one constraint can be that a team can have only 4 batsmen, 5 bowlers and 2 all rounders. Or a team can have constraint that it can have 3 batsmen, 6 bowlers and 2 all rounders.

So is there a particular design pattern for such a scenario?

There isn't.

Summing up (from the comments below) you can have a maximum of 11 players. That's the constraint.

I would solve it easily by getting the number of two kinds of players as arguments in the constructor --- for example Team::Team(int batsmen, int bowlers) --- and computing the other number as difference:

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

To actually say anything meaningful about this, I'd need a lot more information, about the game, and about the future.

I can only guess where the question was aiming to go. At one point they would probably be asking "what if the constraint was that batsman shouldn't weight more than 80kg?)

SOmething along the lines of:

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

As you can see, constraints are separate from the Team class. This way you're going to follow SOLID principles.

You can:

1) add new team configurations dynamically

2) create new constraints dynamically without modifying existing system.

As for your question; there is no "cricket game design pattern". You could use few different patterns when trying to solve this problem, one suits the problem a bit better than other, etc..

What I've essentially done here is that I've used " bridge pattern " in order to

Decouple an abstraction from its implementation so that the two can vary independently.

when speaking about relationship between Team & TeamConstraint.

This is not so much about a specific design pattern.

I think the point of such a question (especially in an interview) is that you flesh out various design options. For example let's start with

class AbstractPlayer
{ /* stuff */ };

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

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

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

Then you could go for

class Team
{
public:
    void addPlayer(Batsman player);
    void addPlayer(Bowler player);
    void addPlayer(AllRounder player);

    /* stuff */ 
};

Alternatively it could be

class Team
{
public:
    void addBatsman(AbstractPlayer player);
    void addBowler(AbstractPlayer player);
    void addAllRounder(AbstractPlayer player);

    /* stuff */ 
};

Anyway you have to decide whether you

  1. store those players in one list of AbstractPlayer s and count the numbers of different player types in different integer properties or
  2. store the players in three different lists of dynamic length

So far so good, now assume somehow you have the number of player types in the Team class. Where are the constraints? They could be set as three maximum counts in the constructor

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

or there could be some kind of setter method (if for one Team instance the numbers may change)

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

There are even more ways I can think of. How about a constraint class? But that depends on the requirements on the Team class.

You could use a simple Specification pattern :

class MyTeamPlayersSpecification {

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

Whether the Specification is verified once at Team construction or in a Validate() method each time you add a player depends on the problem context and your personal preference.

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

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM