How to extend states from multiple classes
How to extend states from multiple classes
(Please note: knowledge of the trading card game Magic: The Gathering will be a plus here. Sorry, I don't know how to put it any easier.)
I have hit upon a problem using Java, which I'll describe as follows... I have a fundamental class called Card with all the following attributes:
public class Card{ String Name; String RulesText; String FlavorText; String Cost; int ConvertedCost; String Rarity; int Number; }
The Permanent class extends Card, and is extended in turn by the classes Creature, Planeswalker, Artifact, Land and Enchantment. As of yet, among them, only the first two have fields of their own:
public class Creature extends Permanent{ int Power; int Toughness; } public class Planeswalker extends Permanent{ int Loyalty; }
Problems:
- Some Permanent objects may be subject to methods affecting an object of its subclasses, for example, both as Artifacts AND Creatures, or as Artifacts AND Lands. I know I can use interfaces to extend behavior, but I cannot do that to extend state unless I use abstract classes, and in some instances I need an object with the state of both Artifacts and Creatures.
- Most Permanent objects of a given subclass cannot be affected by a method targeting an object of a different subclass. (I.e., a method targeting Enchantment objects only cannot affect Creature objects.)
Answer by elekwent for How to extend states from multiple classes
Edit: Although this seems like an inheritance problem that would benefit from simple restructuring, I'll defer to those with Magic experience.
Answer by Nathan Hughes for How to extend states from multiple classes
I think you have more problems than you know. There's a difference between a card and a Permanent, a card performs an effect, like summoning a creature, while the Permanent resulting from the summoning is the creature in play. The card gets used in the game to represent both things for convenience but during programming you will want to distinguish between them.
MTG has cases where Permanents are not related directly to a card (cards like The Hive generate creatures represented only by tokens, they do not have a card representation), so your inheritance hierarchy does not work for that. While you will need to keep a linkage between a card and the creature summoned by it (so you know when to send the card back to the discard pile), I don't think the specific inheritance relationship you have laid out is going to be useful. You may need one hierarchy for cards and another different one for Permanents. Don't ignore the possibility of hierarchies (because there are many inheritance relationships that can be leveraged usefully), just be careful to keep separate things separate.
I would recommend reading Steve Yegge's blogpost on the Universal Design Pattern, where he talks about using a Properties pattern for his game (which seems about as flexible as MTG). Obviously a lot of characteristics of things in the game are mutable (including what's a creature and what isn't, since there are cards that change lands to creatures) and a system for handling properties and changes to them (including expiring temporary changes) is going to be essential. By itself a class hierarchy is not going to be flexible enough to accommodate the variety of effects in MTG.
What makes MTG interesting is that you have this ostensible subject-matter domain (composed of things like Creatures, Spells, Artifacts, Lands, etc.) that seems understandable and solid, but the rules allow these things to change in unpredictable ways (especially since new cards can always be introduced). The subject-matter domain is implemented through a game domain (the set of rules that manipulate the subject-matter domain). If you hard-code the subject-matter domain into your implementation (by doing things like representing Lands or Artifacts by extending a super class or implementing an interface) there are always going to be things you run into that you can't do, and fixing these problems may be hard or impossible. Read the rules noting the technical terminology introduced (cards, permanents, tokens, effects, etc.), because that's the real domain that you need to be implementing.
Answer by Speck for How to extend states from multiple classes
Consider using a StateMachine for this.
You'd have a CreatureStateMachine as well as an ArtifactStateMachine. An object implementing both interfaces can be passed to either StateMachine. Each StateMachine would be responsible for managing the values of a different set of attributes.
The object itself would generate events and pass them to the StateMachines which would either ignore or deal with them accordingly. The StateMachine updates the State of the object being managed and the Object itself only knows what State it is in.
Answer by Remy Porter for How to extend states from multiple classes
You're going to have worse problems when you start dealing with Artifact Creatures, or Artifact Lands and so on.
You need to rethink the IS-A relationships in your model. Multiple inheritance isn't going to be a possibility. But you might be able to use certain design patterns- things like the Visitor pattern or the Delegate pattern may be useful. Effects may use the Command pattern. It may even be useful to have a member of you base class be "TypeTags"- a list of all valid targeting rules.
For example, you may create a creature(pseudocode):
Creature thing = new Creature("My Name", toughness, power, {artifact,creature,enchantment});
Each "Effect" operation would accept a Card object:
Card doEffect(InCard, validTargets) { if (validTargets.Intersection(Incard.targets).length > 0) //we have valid targets return actuallyDoEffect(InCard); else return InCard; }
Answer by Jay for How to extend states from multiple classes
I don't know this game at all, but just going by what you say here:
It is possible that a multi-level hierarchy would address your problems. Like if both Artifacts and Lands have some common behavior, then instead of saying Artifact extends Permanent and Land extends Permanent, you could create another class, let's call it Property, and then say Property extends Permanent, Artifact extends Property, Land extends Property. (I'm thinking "property" in the sense of "real property" and "personal property", not a property of an object. Whatever.) Then any functions or data common to both Artifact and Land could be in Property.
But if there is behavior common to Artifact and Land that is not applicable to Creature, and other behavior common to Artifact and Creature that is not applicable to Land, this approach won't work.
A Java class can't extend more than one other class, but of course it can implement any number of classes. So you could create interfaces for the common behavior for any given set of objects, like maybe a Movable interface that would be implemented by Artifact and Creature, and a Property interface that would be implemented by Artifact and Land, etc. But as I'm sure you realize, this only inherits the declarations, not the code. So you would end up having to implement the same code multiple times.
One thing I've done on occassion is to create another class to implement the behavior, and then the "real" class just forwards everything to the utility class. So if -- and again I don't know the game, so I'm just making up examples -- both Artifact and Land need a "buy" function, you could create a Property interface that both Artifact and Land extend, create a PropertyImplementation class that includes the actual code, and then you'd have something like:
public class PropertyImplementation { public static void buy(Property property, Buyer buyer, int gold) { buyer.purse-=gold; property.owner=buyer; ... etc, whatever ... } } public interface Property { public static void buy(Property property, Buyer buyer, int gold); } public class Land extends Permanent implements Property { public void buy(Buyer buyer, int gold) { PropertyImplementation.buy(this, buyer, gold); } ... other stuff ... } public class Artifact extends Permanent implements Property { public void buy(Buyer buyer, int gold) { PropertyImplementation.buy(this, buyer, gold); } ... other stuff ... }
The less-sophisticated but sometimes quite practical approach is to just throw errors when inapplicable calls are made. Like:
public class Permanent { public void buy(Buyer buyer, int gold) throws InapplicableException { buyer.purse-=gold; this.owner=buyer; ... etc ... } } public class Plainsman extends Permanent { // override public void buy(Buyer buy, int gold) throws InapplicableException { throw new InapplicableException("You can't buy a Plainsman! That would be slavery!"); } }
Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72
0 comments:
Post a Comment