I rather avoid things like
ViewStatus viewStatus;
since it introduces a new class without giving you anything in return when compared to
boolean isViewed;
But that's a matter of personal taste.
By setting the reference to null
you can have a third value, which is not really good, since you can get an unexpected NPE
somewhere; null
is just no "first class value".
EnumSet pretty much exists specifically for this purpose, but... it seems like just two much overhead. Especially when reading the values in the part of the code that builds the HQL.
The overhead of an EnumSet
is reasonable, it caches the class and an array of all values, and uses a long
for storing the data (as long as the enum
is small enought). Its equals
method is quite fast, but obviously slower than reference comparison. You mentioned using HQL, so most probably the runtime will be dominated by the database access, so IMHO you're needless and premature optimization.
The mutability of the EnumSet
may be a problem sometimes, but there's ImmutableEnumSet in guava.
I'll go for an EnumSet because I want to introduce methods on that enum that wouldn't make sense to be called on ALL. For example ViewStatus.isViewed().
I don't think you stated all your alternatives right. You can have both
enum ViewStatus {VIEWED, UNVIEWED}
and
enum ViewStatuses {VIEWED, UNVIEWED, ALL}
where the second is an replacement for the EnumSet
. That said, I agree with your decision.
This can get confusing... and Magic The Gathering is one that loves to do exceptions to rules. Trying to codify them can often be a challenge.
On the "MonoColored Hybrid" read this and this. And then this for Phyrexian mana.
However, this can boil down to something that is rather sensible.. and doesn't stick too much in a single enum or confuse the next person with an inheritance tree of enums. Enums really 'want' to be simple things, so let them be so. The simpler they are, the easier they are to use, and its a good thing to use enums.
A card has some cost. The good old fashioned lighting bolt is just "R". This is a List of some sort. It could even be empty as in the case of 0 cost artifacts (unless you want to do null object). But its a List.
Each element of the list is a SpellCost object.
A SpellCost would then be composed of:
An EnumMap of costs. The Enum that backs the map would be:
enum Mana {
WHITE,
BLUE,
BLACK,
RED,
GREEN,
COLORLESS
}
And then you would have the EnumMap be as a EnumMap<Mana, Integer>
. Something that was a "R/2" for "Red or two colorless" could then be specified in the EnumMap as: mana.put(Mana.RED,1); mana.put(Mana.COLORLESS,2);
This also handles cards that are described as "R/W G" (such as Naya Hushblade - because not all cards are monocolored hybrids).
The EnumMap and EnumSet are two of forgotten collections that are really nice once you realize what they are and do. They give you type safe entries in a map and are backed by either a simple array or a bitfield. The type safety on it can prevent a number of bugs associated with bitfields. And the type safety on the map is something to think about whoever you've got a Map<String, Object>
and wonder what happens when there's a typo in the String.
Phyrexian mana is then an attribute of the SpellCost. Its a int (though you could do it as a boolean later and yell YAGNI in my general direction). Currently the definition of the cost is "mana or two life" but I wouldn't count on that being the case forever and locking yourself into a boolean now... well.
So, you've got:
public class SpellCost {
EnumMap<Mana, Integer> mana;
int lifeCost;
...
}
And then write the associated methods for it. You might want to write a container for the cost itself rather than leaving it as a bare List
so that you can have appropriate methods against it.
The key design points for this is that it keeps the enum simple as enums aught to be. Any of the complexity of the business logic is kept within the SpellCost
class (and possibly the container class too).
Best Answer
found solution here if anybody needs it...
http://niceideas.ch/roller2/badtrash/entry/java_create_enum_instances_dynamically
and this is the one with compile-time solution:
https://bojanv55.wordpress.com/2015/05/25/java-dynamic-enums/