Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations TouchToneTommy on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

New to OOP - simple question

Status
Not open for further replies.

RichLLR

Technical User
Apr 3, 2009
3
I have a background in relational database modeling and have been trying to get to grips with oop for about a week now. I'm sure I have either missed or am mis-understanding something. As an exercise I am trying to build a small web app based on pontoon using asp.net, Ajax & javascript. Obviously there are better ways to achieve this but this allows me to base the design on what I thought would be a couple of fairly basic objects.

I believe a 'PackOfCards' HasA 'Card'. For instance parameters such as 'cardStyle' belong to 'PackOfCards' while 'suit', 'number' etc belong to 'Card'. My confusion begins with Methods. For instance; 'DisplayCard()' is a member of 'Card' as I'm only ever interested in writing the html for a single card (I would use Draw() as the name but that could get confusing). However 'Shuffle()' would be a member of 'PackOfCards' as you can't and wouldn't want to shuffle a single card. But with the way inheritance works every 'Card' would inherit the method 'Shuffle()' which doesn't seem right to me.

Where have I got turned around? Am I simply being too literal with my objects? Thanks for any help in advance.
 
You can make shuffle private to PackOfCards so Card would not see the method.
 
I believe a 'PackOfCards' HasA 'Card'.
correct
However 'Shuffle()' would be a member of 'PackOfCards' as you can't and wouldn't want to shuffle a single card. But with the way inheritance works every 'Card' would inherit the method 'Shuffle()' which doesn't seem right to me.
only if Card inherts PackOfCards, which it shouldn't. it could have a reference to Deck, but that different than inheritance.

here is an example in c# where Deck as a collection of cards, but cards has not knowledge of a Deck
Code:
public class Card
{
   public string suit {get;set;}
   public int number {get;set;}
}

public class Deck
{
   private IList<Card> cards;

   public Deck(IList<Cards> cards)
   {
      this.cards = card;
   }

   public void Suffle()
   {
       randomize(cards);
   }

   public Card Draw()
   {
       Card card = cards[0];
       cards.Remove(card);
       return card;
   }

   public void ReturnToPile(Card card)
   {
       cards.Add(card);
   }
}
[code]
you could add a reference to Deck
[code]
public class Card
{
   public string suit {get;set;}
   public int number {get;set;}
   public Deck pack_of_cards {get;set;}
}
but this doesn't make much sense. if you think about any card game, do you really care what deck the card came from. there is only ever 1 deck (it could be made of multiple decks, but it's still a deck).

This way Card has a Deck, but it does not inherit Deck and therefore does not inherit Shuffle(). you could shuffle the deck from a card
Code:
card.Deck.Shuffle();
but that doesn't make much sense:) Not all references need to be bi-directional. in the first block of code above Deck has Cards, but Card does not have any knowledge of Deck.

one other bit of info, slightly off topic. I would practice your OOP skills without a GUI. Use the console to output results just to see the text. When you introduce WinForms or WebForms it obfuscates the skills you are trying to develop. Your trying to grasp OOP, not html, page life cycle, drag/drog wizards.

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
A PackOfCards and a Card are two different objects and have too little in common to inherit from each other. They are just different things.

Also, in a simple design (and I can only recommend that you start simple), a Card may be told to display itself and a PackOfCards may also be asked to display itself (which could yield totally different outcomes). In more complex designs, You'd probably have a separate object for doing the display.

+++ Despite being wrong in every important aspect, that is a very good analogy +++
Hex (in Darwin's Watch)
 
in UML terms, Deck (PackofCards) has a composite reference to Card. This means that Deck isn't able to exist without card objects, and is the strongest form of relationship. It doesn't imply any inheritance relationships. As you say, "has a" is a means of defining composite or aggregate relationships.

In inheritance, "is a" is a means of determining whether it's appropriate. For example, if Card inherits deck, that means that "a card is a deck" would be true, and it isn't. Which is why your intuition is telling you that that isn't right.

So, I think you might perhaps be confusing the concepts of inheritance and association.

You can make shuffle private to PackOfCards so Card would not see the method.
If you do this, only PackOfCards can see the Shuffle method, meaning that anyone instantiating a Deck can't shuffle it. Card can't see it, but nobody else can either. Methods by definition aren't private, given that the definition of method is something that an object does that is exposed to the outside world.

One final thing: I agree with Jason, that you don't need to have a card keep track of what deck it's in. There's no practical reason to do so that I can see. In UML terms, this is a "one way association", which is much more common than a two way association.
 
At the risk of complicating things:

While PackOfCards and Card are different things, they might have things in common. From your example, they are both "Displayable". And the PackOfCards.display method may need the Card.display method. That is OK.

In Object Orientation, it is good to think in responsibilities. It may be the PackOfCards' responsibility to be able to display itself, but that does not mean it has to take the full responsibility in every detail itself. It may delegate some of its responsibility to the Card objects it holds. So there is nothing wrong with PackofCards.display to call Card.display for some or all of its members. On the contrary.


+++ Despite being wrong in every important aspect, that is a very good analogy +++
Hex (in Darwin's Watch)
 
cheers for all the responses!

After reading through your responses here... and buying an amazingly overpriced book on OOSD&A rather than relying on websites, I have realised that I was trying to force generalisation relationships onto anything and everything in sight when it appears to be rarer than I first assumed.

based on what I've read here:

'Cards' has a Composite relationship to 'Card'. splits into 'Deck' and a 'Cards' class maintaining style information (is this an acceptable use for a class?. If I want to set style information I don't want to set it everytime I instantiate a Card).

so this gives me:

'Cards' - style infomation.

'Card' - inherits 'Cards'

'CardCollection' - contains Shuffle() & GenerateCardCollection(numDecks). strongly typed collection class. inherits CollectionBase. with some overloading/overriding will give alot of the arraylist methods.

Again thanks for the help
 
I was thinking of further breaking down the 'CardCollection' into 'Deck' and 'Hand'. I would like to use it to maintain both types of card collection and I suppose this would prevent 'Hand' having access to GenerateCardCollection() which would be moved to 'Deck'.

Anyway I'm probably getting carried away now :)
 
I was thinking of further breaking down the 'CardCollection' into 'Deck' and 'Hand'.
Hand is a context for a set of cards. while playing a game (5 card draw, go fish, etc) you are dealt an initial hand. each person takes a turn. with each turn you play a card, take a card, discard. all modifying the hand that you hold.

'Cards' has a Composite relationship to 'Card'. splits into 'Deck' and a 'Cards' class maintaining style information
I don't think you need a 'Cards' class. you have
Card : 2-A C,S,H,D
Deck : 52 cards
Game : go fish, 5 card draw, texas hold'em. Each game has it's own set of rules
Hand : a snap shot of the a players cards at any point in time during the game.

If I want to set style information I don't want to set it everytime I instantiate a Card).
Create a factory object to reduce duplicate code. This factory would, most likely, be part of the internal plumbing and not part of the public API.

In the simplest terms the public API would probably look something like this.

//behind the scenes the deck is loaded, and shuffled.
//hands are dealt to all players.
var game = Game.Play("rummy");

//when it's your turn.
var card = deck.draw()
hand.Add(card);
//or
var card = hand.select_card("2S"); //2 of spades
hand.Discard(card);
//or something else

how Game.Play() works behind the scenes is completely up to you. you may have an object to create a deck of 52 cards maybe another one to create 52 cards plus 2 jokers. you may have another object which styles the card as they are created. then you would have a series of objects which creates the specific game the person wants to play. this would need the deck(s) of cards, the rules of the game, the number of players, etc.

One aspect of programming you are scratching the surface of is Domain Driven Design. Eric Evans wrote a book Domain Driven Design (the big blue book). Which is an excellent resource on the subject. in a nutshell, the objects (entities, value objects, services, etc) in your system should reflect the language and terminology of the model you are replicating in code. The fancy term for this is 'ubiquitous language'.

Don't try to plan everything up front. know as Big Design Up Front BDUF. Code what you know. as the domain model becomes more explicit refactor the existing code as necessary. The example I see throughout your most recent post is styling. style the card, style the deck. If you find overlap as your a coding, refactor card and deck to use a common styling component.

There are a bunch of other stuff we could overwhelm you with.
SOLID design principles
Design patterns Patterns
etc.
I will say this though. favor composition over inheritance. In the context of style. that would mean
Code:
class Card
{
    IStyle style {get;set;}
}

class Deck
{
    IStyle style {get;set;}
}

interface IStyle
{
   color,
   pattern,
   whatever();
}
instead of
Code:
class Card : IStyle
{
  // implementation of style
}

class Deck : IStyle
{
  // implementation of style
}

interface IStyle
{
   color,
   pattern,
   whatever();
}
so I'll throw one more tidbit in here. the composition of IStyle for Deck and Card is an example of the strategy pattern. Ok, i'll stop there for this post:)

Jason Meckley
Programmer
Specialty Bakers, Inc.
 
DonQuichote makes a great point. Now I'm thinking that the Composite pattern applies here as well...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top