I'm making a plugin that handles Quests in a game. I have a Quest class that is the instance of a Quest, this is attached to the player's object. I can get the Quest, check it's objectives, which are complete and which aren't etc.
I have four types of Objectives (Talk, Kill Entity, Collect Item, Craft Item). This is stored in an enum. I'm trying to figure out how I can make my Objective class as efficiently as possible, this would require me to init the Objective class with the objective type then the target (the NPC to talk to or the item to collect etc.) but the target would be of a different type depending on the ObjectiveType.
eg: Objective newObjective = new Objective(ObjectiveType.TALK, NPC(10));
would create an objective telling the player to talk to the NPC with the ID 10
Objective newObjective = new Objective(ObjectiveType.COLLECT_ITEM, Item(ZOMBIE_ESSENCE));
would create an objective telling the player to collect one Zombie Essence.
Any help is much appreciated.
Enums cannot be have their own generic types yet (I think there is a JSR for that though). That means that you cannot really tie the ObjectiveType
and its argument together. Otherwise, you could have made Objective
generic:
// this is not possible yet
enum ObjectiveType<T> {
TALK<NPC>,
COLLECT_ITEM<Item>,
...
}
class Objective<T> {
public Objective(ObjectiveType<T> type, T argument) { ... }
}
However, what you can easily do is make the constructor(s) private and use factory methods:
public static Objective newTalkObjective(NPC npc) {
return new Objective(ObjectiveType.TALK, npc);
}
public static Objective newCollectItemObjective(Item item) {
return new Objective(ObjectiveType.COLLECT_ITEM, item);
}
Assuming that NPC and item are classes I can think of a number of ways to do this: Create multiple constructors:
public Objective(NPC npc){
...
}
public Objective(Item item){
...
}
The constructor used will also indicate the type of objective. So, no need to pass that in.
A second way would be to make NPC and Item extend a base class. In this way you will only need one constructor for Objective with the second parameter being the of the type of the base class.
But, IMHO, the correct way to go is actualy to have Objective as a base class and extend it for each type of objective. This will make the code MUCH clearer. Any shared values and methods would go in the base class and the specific ones per objective type would go in the child class.
It will also make it much easier to add more objective types in the future because all you have to do is create another class that extends Objective.
Objective
Any Objective
instance is very similar to a Event
instance.
A common design of EventBus is use a sub-class tree to describe any EventType
s.
This should be efficient if you take enough abstraction of whole Objective module: BaseObjective
, EntityObjective
, MonsterObjective
, KillMonsterObjective
...
class Objective
{
ObjectiveType type;
public Objective(ObjectType type) { this.type = type; }
}
class ObjectiveKillTarget extends Objective
{
TargetType typeTarget; // any extra parameters
public ObjectiveKillTarget(TargetType typeTarget)
{
super(ObjectiveType.KILL_TARGET);
this.typeTarget = typeTarget;
}
}
Map<String, ?>
or something like thatIf you DO want to store all data into instances of ONE class, Map<String, ?>
could help.
It is not recommended but works.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.