Sign in to follow this  
The Orange Peanut

Abstract classes in Java need definition?

Recommended Posts

Must abstract classes define methods which their superclasses intend to use? For example, I have two classes, Card and NumericCard. Card is abstract with 2 variables, neither of which are abstract, and no methods. NumericCard extends Card and (should) add four methods, get/set suit/value, respectively. In my main method, I instantiate a NumericCard object like this: Card card = new NumericCard(); and it compiles fine. The problem is that it doesn't recognize my get and set methods as existing. However, if I go to my Card class and declare an abstract method get/set, my main method compile and work properly. That makes me wonder: how do I add a method to my NumericCard class without adding that same abstract method to my Card class? Or am I doing something wrong? Thanks, I hope I got my question across in a clear manner. I'd be glad to clear something up if I didn't, though.

Share this post


Link to post
Share on other sites
jfclavette    1058
Quote:
Original post by The Orange Peanut
Must abstract classes define methods which their superclasses intend to use? For example, I have two classes, Card and NumericCard. Card is abstract with 2 variables, neither of which are abstract, and no methods. NumericCard extends Card and (should) add four methods, get/set suit/value, respectively. In my main method, I instantiate a NumericCard object like this:

Card card = new NumericCard();

and it compiles fine. The problem is that it doesn't recognize my get and set methods as existing. However, if I go to my Card class and declare an abstract method get/set, my main method compile and work properly. That makes me wonder: how do I add a method to my NumericCard class without adding that same abstract method to my Card class? Or am I doing something wrong?

Thanks, I hope I got my question across in a clear manner. I'd be glad to clear something up if I didn't, though.


You can add them, but then you need to declare them as NumericCard, and not Card. If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.

Share this post


Link to post
Share on other sites
Quote:
Original post by jfclavette

If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.


Yes, I tried that and it worked, but I think it might defeat the purpose of what I was trying to do. My intent was to have a collection of Card objects (which is more than likely going to be a vector) that is filled with NumericCard objects and RoyalCard objects (also extended from Card). Isn't that what polymorphism is about?

Share this post


Link to post
Share on other sites
jfclavette    1058
Quote:
Original post by The Orange Peanut
Quote:
Original post by jfclavette

If you have a reference to a Card, you can only call Card methods.

NumericCard card = new NumericCard();

should allow you to call the methods that aren't in Card.


Yes, I tried that and it worked, but I think it might defeat the purpose of what I was trying to do. My intent was to have a collection of Card objects (which is more than likely going to be a vector) that is filled with NumericCard objects and RoyalCard objects (also extended from Card). Isn't that what polymorphism is about?


Yes, polymorphism is about providing different level of abstractions for a type hierarchy and to permit to implement different way to respond to messages (method call) of a general group of object without caring about the gritty details of each particular object.

In that case, when you go trough your array, how the hell will you know wether your card supports a certain method ? If all card types support a method, it goes in the general card class (You can add it only as an abstract method and provide two different implementations for the different card types). If it's a method specific to a certain type, it goes in the subclass. But then, when you are treating the deck as a whole, you have to hold back to the level of abstractions that all the cards support, hence the methods declared in Card.

Share this post


Link to post
Share on other sites
Zahlman    1682
First, ask yourself why a NumericCard would be able to do things that a RoyalCard couldn't, or vice-versa. Then, understand that, given something that you only *know* is a Card, that it is unreasonable to expect to do either NumericCard- or RoyalCard-specific things with it. What if it turned out to be the other kind?

In general (trying to keep this principle language-agnostic too), you don't want to put derived classes into a container and then try to use their specific interfaces. The polymorphism is useful here only for varying the implementation of the common interface. The container can't "remember" the types, and *if* you can statically prove the exact type of each element, all the time, then it's almost certain that you don't really have any good reason for putting them in the *same* container.

Then, ask yourself why the two would even do things in a different *way*. Why are you creating this inheritance hierarchy at all?

Share this post


Link to post
Share on other sites
Fred304    382
Quote:
Original post by The Orange Peanut
Card is abstract with 2 variables, neither of which are abstract, and no methods.

Did you create the abstract Card class just to save some typing? So you do not have to declare the 2 variables in both subclasses? I would not recommend that. I even fear you might have declared them as public ;)

If you really need the distinction between a NumericCard and RoyalCard, declare an interface Card with all the relevant operations and have the two classes implements them as methods.

public interface Card
{
void foo(int x);
boolean bar();
}

public class NumericCard implements Card
{
private int a, b; // the two fields you mentioned

public void foo(int x)
{
// NumericCard implementation of foo
}

public boolean bar()
{
boolean result;
// NumericCard implementation of bar
return result;
}
}

public class RoyalCard implements Card
{
private int a, b; // the two fields you mentioned

public void foo(int x)
{
// RoyalCard implementation of foo
}

public boolean bar()
{
boolean result;
// RoyalCard implementation of bar
return result;
}
}


Share this post


Link to post
Share on other sites
Well, the idea was that NumericCard would add nothing to Card except the get and set methods, and override the toString method which would return a string in the form value + " of " + suit. Then RoyalCard would add another variable, name, that would indicate if it was a king, jack, queen, or whatever since they all have the same value and the toString overrided method would instead be implemented as returning name + " of " + suit.

Anyway, I see what you are saying about the generic class needing the declarations for both classes. Though, I think I should, like another poster said, use interfaces instead. Thanks again, all of you.

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by The Orange Peanut
Well, the idea was that NumericCard would add nothing to Card except the get and set methods, and override the toString method which would return a string in the form value + " of " + suit. Then RoyalCard would add another variable, name, that would indicate if it was a king, jack, queen, or whatever since they all have the same value and the toString overrided method would instead be implemented as returning name + " of " + suit.


In both cases you do provide basically the same toString: some identifier for the rank + " of " + suit. You don't need to store "names" for RoyalCards. Instead, store the value - for example, 1 for ace, 11 for jack, 12 for queen, 13 for king - and *decode* that value in the toString(). The same method works just fine for the NumericCards. You could for example just hold a static table with the rank names, and use the rank to index in (although in that case you will want the numeric "rank values" to start at 0, so a bit of arithmetic may be needed).

And why would you be able to get or set a NumericCard but not a RoyalCard?

Share this post


Link to post
Share on other sites
Fred304    382
Quote:
Original post by The Orange Peanut
override the toString method which would return a string in the form value + " of " + suit.

Give enumerations a try!


public enum Suit
{
DIAMONDS,
HEARTS,
SPADES,
CLUBS;

public String toString()
{
return super.toString().toLowerCase();
}
}

public enum Rank
{
TWO (2, "2"),
THREE (3, "3"),
FOUR (4, "4"),
FIVE (5, "5"),
SIX (6, "6"),
SEVEN (7, "7"),
EIGHT (8, "8"),
NINE (9, "9"),
TEN (10, "10"),
JACK (1, "jack"),
QUEEN (1, "queen"),
KING (1, "king"),
ACE (1, "ace");

private int _value;
private String _name;

private Rank(int value, String name)
{
_value = value;
_name = name;
}

public int getValue()
{
return _value;
}

public String toString()
{
return _name;
}
}

public class Card
{
private Rank _rank;
private Suit _suit;
private String _string;

public Card(Rank rank, Suit suit)
{
_rank = rank;
_suit = suit;
_string = _rank + " of " + _suit;
}

public Rank getRank()
{
return _rank;
}

public Suit getSuit()
{
return _suit;
}

public int getValue()
{
return _rank.getValue();
}

public String toString()
{
return _string;
}
}

public class Test
{
public static void main(String[] args)
{
Card card = new Card(Rank.ACE, Suit.SPADES);
System.out.print("the only card you need is the " + card);
}
}


Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this