Consider a multiplayer fighting game, where the client selects a fighter by sending to the server a string that contains the name of the fighter the client just selected.
Consider this "fighters" class structure in the server:
Fighter
Foo extends Fighter
Bar extends Fighter
Qux extends Fighter
For instance the client sent this "Bar" string, how can I initiate a subclass according to this string?
The way I did it is an enum like so:
public enum Champion {
Foo {
@Override
public Fighter getNew() {
return new Foo();
}
},
Bar {
@Override
public Fighter getNew() {
return new Bar();
}
},
Qux {
@Override
public Fighter getNew() {
return new Qux();
}
};
public abstract Fighter getNew();
public static boolean contains(String fighter) {
for (Champion c : Champion.values()) {
if (c.name().equals(fighter)) {
return true;
}
}
return false;
}
}
Then I am getting an object like so:
public Fighter getFighter(String fighterName) {
if(Champion.contains(fighterName)) {
return Champion.valueOf(fighterName).getNew();
} else {
return null;
} // For example sake only :)
}
Is this the correct way to deal with this encounter? is there a better way? I remember there is a known pattern to deal with such encounters, but cannot remember exactly which.
If you have an idea please let me know!
Using factories, a solution could look like this:
interface FighterFactory {
Fighter create();
}
Keep a Map<String, FighterFactory> variable in your facade. Each Fighter type has to be registered in this map with its Factory.
private Map<String, FighterFactory> fighters;
public void register(String name, FighterFactory factory) {
fighters.put(name, factory);
}
In each Fighter type embed an inner class Factory e.g.
class Foo extends Fighter {
//code for Foo
public static class Factory implements FighterFactory {
public Foo create() {
return new Foo();
}
}
}
// and in your Facade
register("Foo", new Foo.Factory());
To instantiate a new Fighter do a get to the Fighter-Map and execute create on its result.
FighterFactory factory = fighters.get(nameFromClient);
// null handling, if nameFromClient is not a Fighter type;
return factory.create();
This design has some advantages over reflection:
and over the single factory method (one method handles all Fighter types):
and over the enum approach:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With