In my program, the user needs to input what type of players the game will have. The players are "human", "good" (for a good AI), "bad" (for a bad AI) and "random" (for a random AI). Each of these players have their own class that extend one abstract class called PlayerType.
My struggle is mapping a String to the object so I can A) create a new object using the String as sort of a key and B) get the related String from an object of its subclass
Ultimately, I just want the implicit String to only appear once in the code so I can change it later if needed without refactoring.
I've tried using just a plain HashMap, but that seems clunky with searching the keys via the values. Also, I'm guessing that I'll have to use the getInstance() method of Class, which is a little less clunky, which is okay if it's the only way.
What I would do is create an enum which essentially functions as a factory for the given type.
public enum PlayerTypes {
GOOD {
#Override
protected PlayerType newPlayer() {
return new GoodPlayer();
}
},
BAD {
#Override
protected PlayerType newPlayer() {
return new BadPlayer();
}
},
RANDOM {
#Override
protected PlayerType newPlayer() {
return new RandomPlayer();
}
};
protected abstract PlayerType newPlayer();
public static PlayerType create(String input) {
for(PlayerTypes player : PlayerTypes.values()) {
if(player.name().equalsIgnoreCase(input)) {
return player.newPlayer();
}
}
throw new IllegalArgumentException("Invalid player type [" + input + "]");
}
)
Because then you can just call it like so:
String input = getInput();
PlayerTypes.create(input);
Of course, you'll get an IllegalArgumentException which you should probably handle by trying to get the input again.
EDIT: Apparently in this particular case, you can replace that loop with just merely
return PlayerTypes.valueOf(input).newPlayer();
And it'll do the same thing. I tend to match for additional constructor parameters in the enum, so I didn't think of using valueOf(), but it's definitely cleaner.
EDIT2: Only way to get that information back is to define an abstract method in your PlayerType class that returns the PlayerTypes enum for that given type.
public class PlayerType {
public abstract PlayerTypes getType();
}
public class GoodPlayer extends PlayerType {
#Override
public PlayerTypes getType() {
return PlayerTypes.GOOD;
}
}
I like the answer provided by Epic but I don't find maps to be clunky. So it's possible to keep a map and get the constructor call directly.
Map<String, Supplier<PlayerType> map = new HashMap<>();
map.put("human", Human::new);
Human h = map.get("human").get();
The two main options I can think of:
Using Class.newInstance(), as you mentioned (not sure if you had this exact way in mind):
// Set up your map
Map<String, Class> classes = new HashMap<String, Class>();
classes.put("int", Integer.class);
classes.put("string", String.class);
// Get your data
Object s = classes.get("string").newInstance();
You could use Class.getDeclaredConstructor.newInstance if you want to use a constructor with arguments (example).
Another option is using switch:
Object getObject(String identifier) {
switch (identifier) {
case "string": return new String();
case "int": return new Integer(4);
}
return null; // or throw an exception or return a default object
}
One potential solution:
public class ForFunFactory {
private ForFunFactory() {
}
public static AThing getTheAppropriateThing(final String thingIdentifier) {
switch (thingIdentifier) {
case ThingImplApple.id:
return new ThingImplApple();
case ThingImplBanana.id:
return new ThingImplBanana();
default:
throw new RuntimeException("AThing with identifier "
+ thingIdentifier + " not found.");
}
}
}
public interface AThing {
void doStuff();
}
class ThingImplApple implements AThing {
static final String id = "Apple";
#Override
public void doStuff() {
System.out.println("I'm an Apple.");
}
}
class ThingImplBanana implements AThing {
static final String id = "Banana";
#Override
public void doStuff() {
System.out.println("I'm a Banana.");
}
}
Related
In Java, how can you pass a type as a parameter (or declare as a variable)?
I don't want to pass an instance of the type but the type itself (eg. int, String, etc).
In C#, I can do this:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
Is there a way in Java without passing an instance of type t?
Or do I have to use my own int constants or enum?
Or is there a better way?
Edit: Here is the requirement for foo:
Based on type t, it generates a different short, xml string.
The code in the if/else will be very small (one or two lines) and will use some private class variables.
You could pass a Class<T> in.
private void foo(Class<?> cls) {
if (cls == String.class) { ... }
else if (cls == int.class) { ... }
}
private void bar() {
foo(String.class);
}
Update: the OOP way depends on the functional requirement. Best bet would be an interface defining foo() and two concrete implementations implementing foo() and then just call foo() on the implementation you've at hand. Another way may be a Map<Class<?>, Action> which you could call by actions.get(cls). This is easily to be combined with an interface and concrete implementations: actions.get(cls).foo().
I had a similar question, so I worked up a complete runnable answer below. What I needed to do is pass a class (C) to an object (O) of an unrelated class and have that object (O) emit new objects of class (C) back to me when I asked for them.
The example below shows how this is done. There is a MagicGun class that you load with any subtype of the Projectile class (Pebble, Bullet or NuclearMissle). The interesting is you load it with subtypes of Projectile, but not actual objects of that type. The MagicGun creates the actual object when it's time to shoot.
The Output
You've annoyed the target!
You've holed the target!
You've obliterated the target!
click
click
The Code
import java.util.ArrayList;
import java.util.List;
public class PassAClass {
public static void main(String[] args) {
MagicGun gun = new MagicGun();
gun.loadWith(Pebble.class);
gun.loadWith(Bullet.class);
gun.loadWith(NuclearMissle.class);
//gun.loadWith(Object.class); // Won't compile -- Object is not a Projectile
for(int i=0; i<5; i++){
try {
String effect = gun.shoot().effectOnTarget();
System.out.printf("You've %s the target!\n", effect);
} catch (GunIsEmptyException e) {
System.err.printf("click\n");
}
}
}
}
class MagicGun {
/**
* projectiles holds a list of classes that extend Projectile. Because of erasure, it
* can't hold be a List<? extends Projectile> so we need the SuppressWarning. However
* the only way to add to it is the "loadWith" method which makes it typesafe.
*/
private #SuppressWarnings("rawtypes") List<Class> projectiles = new ArrayList<Class>();
/**
* Load the MagicGun with a new Projectile class.
* #param projectileClass The class of the Projectile to create when it's time to shoot.
*/
public void loadWith(Class<? extends Projectile> projectileClass){
projectiles.add(projectileClass);
}
/**
* Shoot the MagicGun with the next Projectile. Projectiles are shot First In First Out.
* #return A newly created Projectile object.
* #throws GunIsEmptyException
*/
public Projectile shoot() throws GunIsEmptyException{
if (projectiles.isEmpty())
throw new GunIsEmptyException();
Projectile projectile = null;
// We know it must be a Projectile, so the SuppressWarnings is OK
#SuppressWarnings("unchecked") Class<? extends Projectile> projectileClass = projectiles.get(0);
projectiles.remove(0);
try{
// http://www.java2s.com/Code/Java/Language-Basics/ObjectReflectioncreatenewinstance.htm
projectile = projectileClass.newInstance();
} catch (InstantiationException e) {
System.err.println(e);
} catch (IllegalAccessException e) {
System.err.println(e);
}
return projectile;
}
}
abstract class Projectile {
public abstract String effectOnTarget();
}
class Pebble extends Projectile {
#Override public String effectOnTarget() {
return "annoyed";
}
}
class Bullet extends Projectile {
#Override public String effectOnTarget() {
return "holed";
}
}
class NuclearMissle extends Projectile {
#Override public String effectOnTarget() {
return "obliterated";
}
}
class GunIsEmptyException extends Exception {
private static final long serialVersionUID = 4574971294051632635L;
}
Oh, but that's ugly, non-object-oriented code. The moment you see "if/else" and "typeof", you should be thinking polymorphism. This is the wrong way to go. I think generics are your friend here.
How many types do you plan to deal with?
UPDATE:
If you're just talking about String and int, here's one way you might do it. Start with the interface XmlGenerator (enough with "foo"):
package generics;
public interface XmlGenerator<T>
{
String getXml(T value);
}
And the concrete implementation XmlGeneratorImpl:
package generics;
public class XmlGeneratorImpl<T> implements XmlGenerator<T>
{
private Class<T> valueType;
private static final int DEFAULT_CAPACITY = 1024;
public static void main(String [] args)
{
Integer x = 42;
String y = "foobar";
XmlGenerator<Integer> intXmlGenerator = new XmlGeneratorImpl<Integer>(Integer.class);
XmlGenerator<String> stringXmlGenerator = new XmlGeneratorImpl<String>(String.class);
System.out.println("integer: " + intXmlGenerator.getXml(x));
System.out.println("string : " + stringXmlGenerator.getXml(y));
}
public XmlGeneratorImpl(Class<T> clazz)
{
this.valueType = clazz;
}
public String getXml(T value)
{
StringBuilder builder = new StringBuilder(DEFAULT_CAPACITY);
appendTag(builder);
builder.append(value);
appendTag(builder, false);
return builder.toString();
}
private void appendTag(StringBuilder builder) { this.appendTag(builder, false); }
private void appendTag(StringBuilder builder, boolean isClosing)
{
String valueTypeName = valueType.getName();
builder.append("<").append(valueTypeName);
if (isClosing)
{
builder.append("/");
}
builder.append(">");
}
}
If I run this, I get the following result:
integer: <java.lang.Integer>42<java.lang.Integer>
string : <java.lang.String>foobar<java.lang.String>
I don't know if this is what you had in mind.
You should pass a Class...
private void foo(Class<?> t){
if(t == String.class){ ... }
else if(t == int.class){ ... }
}
private void bar()
{
foo(String.class);
}
If you want to pass the type, than the equivalent in Java would be
java.lang.Class
If you want to use a weakly typed method, then you would simply use
java.lang.Object
and the corresponding operator
instanceof
e.g.
private void foo(Object o) {
if(o instanceof String) {
}
}//foo
However, in Java there are primitive types, which are not classes (i.e. int from your example), so you need to be careful.
The real question is what you actually want to achieve here, otherwise it is difficult to answer:
Or is there a better way?
You can pass an instance of java.lang.Class that represents the type, i.e.
private void foo(Class cls)
Given these classes:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public class VersionVOV2 extends BaseVO {
private String fieldFour = null;
public String getFieldFour() {
return fieldFour;
}
public void setFieldFour(String fieldFour) {
this.fieldFour = fieldFour;
}
}
public class BaseVO {
// common code here
}
I have a calling method doSomething which returns a specific child class based upon an input string:
public BaseVO doSomething(String version) {
BaseVO versionVO = doSomethingVersioned(createVersionVO(version));
return versionVO;
}
The remaining methods are:
private BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
protected VersionVOV1 doSomethingVersioned(VersionVOV1 versionVO) throws Exception {
versionVO.setFieldOne("The versionVO is of type: " + versionVO.getClass());
versionVO.setFieldTwo("Field two");
versionVO.setFieldThree("Field three");
return versionVO;
}
protected VersionVOV2 doSomethingVersioned(VersionVOV2 versionVO) throws Exception {
versionVO.setFieldOne("The versionVO is of type: " + versionVO.getClass());
versionVO.setFieldThree("Field three");
versionVO.setFieldFour("Field four");
return versionVO;
}
As you can see I've overridden doSomethingVersioned to take in a specific child class. My problem however lies with the compilation error that looks like this on doSomethingVersioned: The method doSomethingVersioned(VersionVOV1) in the type VersionExample is not applicable for the arguments (BaseVO).
I've tried returning a type of <T extends BaseVO> from createVersionVO but then I get other compilation errors in that method stating Type mismatch: cannot convert from VersionVOV1 to T.
I feel like this should be easier than I'm making it. How can I keep this overall pattern but allow this to compile?
Thanks to everyone who helps!
What you want is the pattern Factory Method. Note: there really is no benefit from genericity here. You are merely creating something then the presumption is it will go on its way. Generics tend to yield the greatest benefit when you are wanting to leverage code that is orthogonal to the domain objects, e.g. collections.
Given the following abstract class:
public abstract class BaseVersionResponse<T extends BaseVO> {
public abstract void populate(T versionVO);
}
and the following child class:
public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
protected String testFieldOne;
protected String testFieldTwo;
public String getTestFieldOne() {
return testFieldOne;
}
public void setTestFieldOne(String value) {
this.testFieldOne = value;
}
public String getTestFieldTwo() {
return testFieldTwo;
}
public void setTestFieldTwo(String value) {
this.testFieldTwo = value;
}
#Override
public void populate(VersionVOV1 versionVO) {
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
I desire to do something like this from a calling method:
public void getVersionInfo(String version) {
BaseVO versionVO = null;
BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;
baseVersionResponse = createVersionResponse(version);
versionVO = createVersionVO(version);
baseVersionResponse.populate(versionVO);
}
where createVersionResponse(...) and createVersionVO(...) look like this:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {
BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;
if (version.equalsIgnoreCase("V1")) {
specificVersionResponse = new VersionResponseV1();
} else if (version.equalsIgnoreCase("V2"))
specificVersionResponse = new VersionResponseV2();
return specificVersionResponse;
}
public BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
and VersionVOV1 looks like this:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
private String fieldTwo = null;
private String fieldThree = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public String getFieldThree() {
return fieldThree;
}
public void setFieldThree(String fieldThree) {
this.fieldThree = fieldThree;
}
}
My problem arises when I try to compile this line of code:
baseVersionResponse.populate(versionVO);
in getVersionInfo(...). I'm getting a message that looks like this:
The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)
on the populate method above.
My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class.
What am I doing wrong here? Is there a better way to do this if this isn't the correct approach?
Thank you for your time!
Ok, I took a better look at this today. The problem is that the wildcard, while the right way to go, precludes you from doing:
BaseVO versionVO = createVersionVO(version);
Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. That means you can't pass that versionVO variable directly.
So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like:
public abstract class BaseVersionResponse<T extends BaseVO> {
public T getVersion(BaseVO versionVO) {
try {
return (T) versionVO;
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
}
public abstract void populate(BaseVO versionVO);
}
So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown.
Now, in your response class implementation, change the populate method accordingly:
public void populate(BaseVO version) {
VersionVOV1 versionVO = getVersion(version);
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. All the other type checks still apply, and we're good to go.
The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact.
Hope that helps!
If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. Even using type Object would have compiled.
But, given your specific example, what you probably want is the method:
public BaseVersionResponse<?> createVersionResponse(String version)
Changed to:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
Then, instead of using
BaseVersionResponse<?>
use
BaseVersionResponse<? extends BaseVO>
Since you know that the return type will be one of those things that implements the interface/class.
I have a string (which is a message) that I get as input and I need to do one of 4 possible things depending on the string
I know that there is eunm.valueOf() option, but I have 4 different enums, each with few possible messages.
looks something like:
public enum first{ONE,TWO,THREE};
public enum second{FOUR,FIVE,SIX};
public enum third{SEVEN,EIGHT,NINE};
public void work(String message){
//Here I want to compare message string to one of the 3 enums
}
is it possible to do this in one method of the enum?
or should I just try to create one, and if I get an exception try the other and so on?
As others have commented, it may be better to think through whether you really need 4 distinct enums.
But if you do, you could have them implement a common interface. Then you can map the input strings to the appropriate enum member, and call its method to accomplish what you want. Something like
public interface SomeInterface {
void doSomething();
};
public enum First implements SomeInterface {
ONE,TWO,THREE;
#Override
public void doSomething() { ... }
};
...
Map<String, SomeInterface> myMap = new HashMap<String, SomeInterface>();
for (First item : First.values()) {
myMap.put(item.toString(), item);
}
...
public void work(String message){
SomeInterface obj = myMap.get(message);
if (obj != null) {
obj.doSomething();
}
}
This assumes that the 4 possible things you want to do correspond to the 4 enums. If not, you can override the method separately for each and any enum member too, e.g.
public enum First implements SomeInterface {
ONE,
TWO {
#Override
public void doSomething() { // do something specific to TWO }
},
THREE;
#Override
public void doSomething() { // general solution for all values of First }
};
Enumerations in Java are full blown classes. Individual values can even override the behavior to meet their needs. It's pretty cool. You can use this to your advantage:
public enum Value implements Worker
{
ONE,
TWO,
THREE
{
#Override
public void doWork(String message)
{
// overrides behavior of base enum
}
},
FOUR,
/* ... */,
NINE;
private final String message;
Value() { this(""); }
Value(String message) { this.message = message; }
public void doWork(String message)
{
if (this.message.equals(message))
{
/* ... */
}
}
}
public interface Worker
{
void doWork(String message);
}
You can create a Map of them all
static final Map<String, Enum> enumMap = new LinkedHashMap<String, Enum>(){{
for(First e: First.values()) put(e.name(), e);
for(Second e: Second.values()) put(e.name(), e);
for(Third e: Third.values()) put(e.name(), e);
}};
Enum e = enumMap.get(name);
What you're really looking for is a aggregation of the other enums. The easiest way to get that is to make a new enum that puts all of those choices in a new enum. Something to this effect:
public enum Combination {
NEWONE(first.ONE), NEWTWO(first.TWO), NEWTHREE(first.THREE),
NEWFOUR(second.FOUR), NEWFIVE(second.FIVE), NEWSIX(second.SIX),
NEWSEVEN(third.SEVEN), NEWEIGHT(third.EIGHT), NEWNINE(third.NINE);
private String contents;
public Combination(first f) {
contents = f.toString();
}
public Combination(second s) {
contents = s.toString();
}
public Combination(third t) {
contents = t.toString();
}
public String toString() {
return contents;
}
}
This will more correctly aggregate the previous enums into a single data structure.
Even given your odd/even example in the comments, I don't feel multiple enums are the way to go here. I would use something like (warning, untested):
public enum Numbers {
ONE("first"), TWO("first"), THREE("first"), FOUR("second"), FIVE("second"), SIX("second"), SEVEN("third"), EIGHT("third"), NINE("third")
private String type;
Numbers(String t) { this.type = t; }
String getType { return this.type; }
}
Then you can use valueOf() to look up the enum element, and getType() to find out which of your three categories it belongs to.
It isn't entirely clear what you are asking, but perhaps you want to define a mapping between strings and constants, like this:
enum Type { FIRST, SECOND, THIRD };
Map<String, Type> mapping = new HashSet<String, Type>(){{
put("ONE", Type.FIRST);
put("TWO", Type.FIRST);
//...
put("NINE", Type.THIRD);
}};
public Type getTypeFromString(String s) {
return mapping.get(s);
}
I'm trying to define a class (or set of classes which implement the same interface) that will behave as a loosely typed object (like JavaScript). They can hold any sort of data and operations on them depend on the underlying type.
I have it working in three different ways but none seem ideal. These test versions only allow strings and integers and the only operation is add. Adding integers results in the sum of the integer values, adding strings concatenates the strings and adding an integer to a string converts the integer to a string and concatenates it with the string. The final version will have more types (Doubles, Arrays, JavaScript-like objects where new properties can be added dynamically) and more operations.
Way 1:
public interface DynObject1 {
#Override public String toString();
public DynObject1 add(DynObject1 d);
public DynObject1 addTo(DynInteger1 d);
public DynObject1 addTo(DynString1 d);
}
public class DynInteger1 implements DynObject1 {
private int value;
public DynInteger1(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject1 add(DynObject1 d) {
return d.addTo(this);
}
public DynObject1 addTo(DynInteger1 d) {
return new DynInteger1(d.value + value);
}
public DynObject1 addTo(DynString1 d)
{
return new DynString1(d.toString()+Integer.toString(value));
}
}
...and similar for DynString1
Way 2:
public interface DynObject2 {
#Override public String toString();
public DynObject2 add(DynObject2 d);
}
public class DynInteger2 implements DynObject2 {
private int value;
public DynInteger2(int v) {
value = v;
}
#Override
public String toString() {
return Integer.toString(value);
}
public DynObject2 add(DynObject2 d) {
Class c = d.getClass();
if(c==DynInteger2.class)
{
return new DynInteger2(value + ((DynInteger2)d).value);
}
else
{
return new DynString2(toString() + d.toString());
}
}
}
...and similar for DynString2
Way 3:
public class DynObject3 {
private enum ObjectType {
Integer,
String
};
Object value;
ObjectType type;
public DynObject3(Integer v) {
value = v;
type = ObjectType.Integer;
}
public DynObject3(String v) {
value = v;
type = ObjectType.String;
}
#Override
public String toString() {
return value.toString();
}
public DynObject3 add(DynObject3 d)
{
if(type==ObjectType.Integer && d.type==ObjectType.Integer)
{
return new DynObject3(Integer.valueOf(((Integer)value).intValue()+((Integer)value).intValue()));
}
else
{
return new DynObject3(value.toString()+d.value.toString());
}
}
}
With the if-else logic I could use value.getClass()==Integer.class instead of storing the type but with more types I'd change this to use a switch statement and Java doesn't allow switch to use Classes.
Anyway... My question is what is the best way to go about something thike this?
What you are trying to do is called double dispatch. You want the method called to depend both on the runtime type of the object it's called on, and on the runtime type of its argument.
Java and other C derivatives support single dispatch only, which is why you need a kludge like the visitor pattern you used in option 1. This is the common way of implementing it. I would prefer this method because it uses no reflection. Furthermore, it allows you to keep each case in its own method, without needing a big "switchboard" method to do the dispatching.
I'd choose the second option, with the third, I'd better be using generics so you don't rely on that Enum. And with the first option you could be implementing methods for the rest of your life. Anyways you could use "instanceof" operator for Class matching.