Backup code as part of the C ++ class

I am trying to pick up C ++. Everything went well until my “practical” program hit me with a very shallow grip. I believe this problem is related to the design problem.

Think of Blackjack (21). I did some classes.

  • cards
  • Deck
  • arm
  • Player

The deck consists of - for simplicity - has an array of cards.
-He can show all the cards
- You can shuffle
-He can remove cards.

Hand - deck - profitably
-He can calculate the value of his hand
-He can add cards in his hand

Now, to get to my problem - player design

-A player has a hand (private access)
My problem with the player is that the hand has a method function called addCardToHand. I feel a sense of redundancy / poor design if I need to create a player method called addCardToHand (card c) in which calls and transfers are in the same method.

or

declare Hand h as a public member and in 'main ()' do something like
Player p;
card card;
phaddCard (Acard);

Any advice would be enlightening and much appreciated. Keep in mind that I'm studying.

+4
source share
2 answers

The best answer here is: it depends :) I will try to clarify this a bit.

First question: Does the Player class have any internal logic? If this is a simple container for Hand, I will just write Player.GetHand().AddCard() , because there is no reason to duplicate the code inside the Player.AddCard() method, and the problem is solved.

Suppose now that there is a need to implement additional logic to add a card to the Player’s hand. This means that additional code in the Player class must be called when adding a card to your hands. In this case, I see three possible solutions.

(Sources for demonstration purposes only, cannot compile)

  • Restrict access to your hand so that no one can extract it from Player. The player would have to implement methods such as AddToHand, RemoveFromHand, etc. Doable, but not convenient to use.

     class Player { private: Hand hand; public: void AddToHand(Card & card) { hand.Add(card); } }; 
  • Use the observer pattern . When a user (class user) calls Player.GetHand (). AddCard (), Hand tells the player that the data has been changed, and Player can act accordingly. You can easily achieve this using std :: function from C ++ 11 to implement events.

     class Deck { private: std::function<void(void)> cardsChanged; public: void Add(Card card) { // Add a card if (!(cardsChanged._Empty())) cardsChanged(); } void SetCardsChangedHandler(std::function<void(void)> newHandler) { cardsChanged = newHandler; } }; // (...) class Player { private: Hand hand; void CardsChanged() { ... } (...) public: Player() { hand.SetCardsChangedHandler([&this]() { this.CardsChanged(); } ); } }; 
  • Define an IHand interface with all the necessary interface methods. The hand should obviously implement IHand and Player.GetHand () should return IHand. The trick is that the IHand returned by the player does not have to be a Hand instance, but instead it can be a decorator acting as a bridge between the user and the real Hand instance (see decorator pattern ).

     class IHand { public: virtual void Add(Card card) = 0; virtual void Remove(Card card) = 0; }; class Hand : public IHand { // Implementations } class PlayersHand : public IHand { private: Hand & hand; Player & player; public: PlayersHand(Hand & newHand, Player & newPlayer) { hand = newHand; player = newPlayer; } void Add(Card card) { hand.Add(card); player.HandChanged(); } // ... }; class Player { private: Hand hand; PlayersHand * playersHand; public: Player() { playersHand = new PlayersHand(hand, this); } IHand GetHand() { return playersHand; } } 

Personally, in the second case, I would choose the second solution - it is quite simple and easy to distribute and reuse in case of further needs.

+3
source

Forwarding function calls is a common practice. You should think of it as adding some level of abstraction. This does not quite repeat the same thing (which means redundancy), but implements one method using another.

In the future, you can imagine some changes, for example, adding the Player cache cache or some other materials that need to be updated when the user calls addCardToHand . Where would you add the cache update code if you did not implement the forwarding method?

Also note that the "interface" Player::addCardToHand does not have to be identical with Card::addCard , i.e. arguments and return value may be different in these functions. Perhaps this is not so important in this case, but in general the forwarding function is the place where some translation can be added between the Player interface and the Hand interface.

0
source

All Articles