I'm working on a game which has different items which all have different behavior. All items can be improved by buying different upgrades for different aspects of the item. I save the player's data in a MongoDB. This data includes an array of documents. Each documents represents one item and contains at least a String holding the item's name. This makes it possible to identify the type and instantiate an object of that type when the player wants to use it.
My plan was to use some sort of service locator to map the names to the factories of the specific item. After reading a lot of similar questions spread across StackExchange I learned that service locator is generally considered an anti-pattern.
The question that comes up now is: What should I do instead? I plan to move the items out of the core and create different expansion packets, which would add new items. These would be added to the service locator, so I somewhat need it or a good alternative to it.
Is my case one of these special cases where service locator isn't the bad anti-pattern which should be avoided or is it considered bad practice even in this kind of usage? What are my possible alternatives?
Thank you for your help!
Example
Some additional information to clarify the given situation: There are different items with different abilities, as an example I will use the easiest one I found. This item shoots some explosives when used. These explosives will explode when they hit something. The item has the following aspects, which may be upgraded:
Other items have different attributes. As each attribute can be upgraded individually there have to be different upgrade lists for each.
Current situation
Right now I have an interface Item
:
public interface Item<T extends Item<T>> {
// Get type of this item
public ItemType<T> getType();
// Serialize for database storage
public Map<String, Object> serialize();
// Get the player owning this item
public Player getOwner();
}
and ItemType<T extends Item<T>>
:
public interface ItemType<T extends Item<T>> {
// create a new item of that type with everything set to default values
public T constructNewItem(Player player);
// deserialize and create item with existing data
public T deserializeItem(Player player, Map<String, Object> serialized);
// Serialize upgrade lists for database storage
public Map<String, Object> serialize();
// Get the item's name
public String getName();
}
I now have a class ItemRegistry* which manages a map containing the registered items' name as keys and the registered items as values(Map<String, ItemType<?>>
). Currently it is a singleton, which is initialized with the available items loaded from a folder, when the application starts. When a player wants to play I load the data, lookup the item to construct with the name given in the loaded data and then deserialize it using ItemType#deserializeItem
. I'm using an ItemType as a workaround because there is now way to create abstract static methods.
Maybe already this setup is one big disaster, so any comments about it are also appreciated.
*Side question: Am I mixing up registry and service locator?