Background
Here's the actual problem I'm working on: I want a way to represent cards in the card game Magic: The Gathering. Most cards in the game are normal-looking cards, but some of them are divided into two parts, each with its own name. Each half of these two-part cards is treated as a card itself. So for clarity, I'll use Card
only to refer to something that's either a regular card, or half of a two-part card (in other words, something with only one name).
So we have a base type, Card. The purpose of these objects is really just to hold properties of the card. They don't really do anything by themselves.
interface Card {
String name();
String text();
// etc
}
There are two subclasses of Card
, which I'm calling PartialCard
(half of a two-part card) and WholeCard
(a regular card). PartialCard
has two additional methods: PartialCard otherPart()
and boolean isFirstPart()
.
Representatives
If I have a deck, it should be composed of WholeCard
s, not Card
s, as a Card
could be a PartialCard
, and that wouldn't make sense. So I want an object that represents a "physical card," that is, something that can represent one WholeCard
, or two PartialCard
s. I'm tentatively calling this type Representative
, and Card
would have the method getRepresentative()
. A Representative
would provide almost no direct information on the card(s) it represents, it would only point to it/them. Now, my brilliant/crazy/dumb idea (you decide) is that WholeCard inherits from both Card
and Representative
. After all, they are cards that represent themselves! WholeCards could implement getRepresentative
as return this;
.
As for PartialCards
, they don't represent themselves, but they have an external Representative
that is not a Card
, but provides methods for accessing the two PartialCard
s.
I think this type hierarchy makes sense, but it's complicated. If we think of Card
s as "conceptual cards" and Representative
s as "physical cards," well, most cards are both! I think you could make an argument that physical cards do in fact contain conceptual cards, and that they're not the same thing, but I would argue that they are.
Necessity of Type-casting
Because PartialCard
s and WholeCards
are both Card
s, and there's usually no good reason to separate them out, I'd normally just be working with Collection<Card>
. So sometimes I'd need to cast PartialCard
s in order to access their additional methods. Right now, I'm using the system described here because I really don't like explicit casts. And like Card
, Representative
would need be cast to either a WholeCard
or Composite
, to access the actual Card
s they represent.
So just for summary:
- Base type
Representative
- Base type
Card
- Type
WholeCard extends Card, Representative
(no access needed, it represents itself) - Type
PartialCard extends Card
(gives access to other part) - Type
Composite extends Representative
(gives access to both parts)
Is this insane? I think it actually makes a lot of sense, but I'm honestly not sure.