I am fairly new to Java, I learned it in college but haven't really touched it much since. I am trying to learn it again and I am making a simple client server game but have run into some issues.
Basically what I am trying to do is make it so that I have a class with all the commands a player can do and I want to call that command based on what they send the server.
Client sends message such as "kill monster".
Server should split the string and call the method kill('monster');
I could obviously map out the commands with a switch but I wanted to try out reflection and dynamically calling the method based on the string sent. This would make my code a bit cleaner I think since I would only need to add new methods and a handler for when there is no such method.
In PHP this is really easy you can just call the function by saying myclass->$mymethod('a string');
I already have the client and server set up to have the client type a string and send it to the server which saves it in the variable message.
What I have tried in Java is this:
String[] parts = message.split(" ", 2);
Command.class.getMethod(parts[0].toLowerCase(), String.class).invoke(parts[1].toLowerCase());
But this does not work for me and I get an error
java.lang.IllegalArgumentException: object is not an instance of declaring class
Command.java is simple and is this:
public class Command {
public Command(){
}
public void kill(String monster){
System.out.println(monster + " Kills you!");
}
}
What am I doing wrong. The one thing I am particularly not sure about is the second parameter of getMethod().
The error itself is because the method that you're trying to invoke is an instance method, and you need an instance of that command to invoke it (right now, you're trying to invoke the kill method on an instance of the String class -- the first argument you're passing). See this answer or the Method.invoke() javadoc for details.
But if you need reflection in your application code, it usually means you're not on the right track (at least from an OOP point of view).
In your particular case, the various commands should not be modeled as methods of the same class, but as instances of it (see command pattern, for instance, or even strategy pattern, as useful examples).
Since you only want to have one instance per command (and you need to find the proper command by name), an enum would probably be the most suitable choice here:
enum Command {
KILL {
#Override public void execute(String arg) {
System.out.printf("%s is dying...", arg)
}
},
KISS {
#Override public void execute(String arg) {
System.out.printf("I'm kissing %s!", arg)
}
};
public abstract void execute(String arg);
}
Then, your code becomes simply:
Command.valueOf(parts[0].toUpperCase()).execute(parts[1].toLowerCase());
Related
I'm very new to programming language. My question might not even make sense. My environment is using java and trying to implement both ios and android apps in the same automation testing framework.
So, the idea is that any test script should be able to run on both the apps. Ex: one signin test script should be run for both ios and android.
I've decided to use interface and class implementation approach. The problem I'm facing is with test data. My company doesn't want to use excel. They want to use json for test data.
Here's my problem, look at the following line of code:
ValidBuy goodBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "good-buy.json", ValidBuy.class);
As you can see I have a class "ValidBuy" that has all the getters for a particular json file. I have another class "JsonFileReader" which takes the json filePath, fileName, and a class as an input and returns the data for that class name that I passed in. For this example I've passed ValidBuy.class
So, when I run a positive test, I'm passing "goodBuy" variable which is of type "ValidBuy". The problem starts here.
The test case is now specified with the data from goodBuy because it's type is "ValidBuy" and I'm passing goodBuy as a parameter.
Look at one of my extracted methods:
private void enterBuyInfo(ValidBuy goodBuy) {
itemPage = nativeApp.getItemPage(goodBuy);
itemPage.setItemName(goodBuy.getItemName());
itemPage.setItemSize(goodBuy.getItemSize());
itemPage.setItemDigitSSN(goodBuy.getSsn());
itemPage.clickContinue();
}
You can see those getters I'm using are coming from ValidBuy class.
If I run this test with the data for a badBuy:
InvalidBuy badBuy = JsonFileReader.loadDaTa(TestBase.DATA_PATH, "bad-buy.json", InvalidBuy.class);
It fails because now I have to change "ValidBuy" class with "InvalidBuy" class. Since, changing the parameter in the extracted method in every run is not possible, how can I make it more generic?
I want something like this:
TestData data = JsonFileReader.loadDaTa(RESOURCES_PATH, "good-client.json", InvalidBuy.class);
Here, TestData is generic. It could either be a class or interface (I don't know if that's possible) and the return type will be specified by whichever class I pass into the loadData() method. In this case InvalidBuy.class
The extracted method should look like this:
private void enterBuyInfo(TestData data) {
itemPage = nativeApp.getItemPage(data);
itemPage.setItemName(data.getItemName());
itemPage.setItemSize(data.getItemSize());
itemPage.setItemDigitSSN(data.getSsn());
itemPage.clickContinue();
}
If I can do this, I can use those extracted methods to create more tests.
I know I wrote a lot. I've only tried to make it as clear as possible. If it doesn't make any sense, just disregard it.
Any suggestions, ideas, code samples will be highly appreciated.
Firstly let me see if I understand your question. I think you are saying that loadData may return a value of type ValidBuy or InvalidBuy and you want to pass into it the class that you want returned. You then want to know how to use an interface that might represent either of these classes in your test methods so you can test various return values (both valid and invalid). You use the term "generic" in your question but I'm guessing you don't mean to use it in the specific way it's used in Java.
If I've understood your question correctly, then here's an answer:
Passing the class you wish to have returned into a method is an unusual usage and almost certainly not ideal. Better OOD would be to extract the common methods for all objects returned from loadData into an interface.
So:
interface Buy {
String getItemName();
boolean isValid();
}
class ValidBuy implements Buy {
#Override
public boolean isValid() {
return true;
}
...
}
class InvalidBuy implements Buy {
#Override
public boolean isValid() {
return false;
}
...
}
class JsonFileReader {
Buy loadData(Path path) {
...
}
}
Then your tests can look like:
#Test
void testValidBuy() {
assertTrue(reader.loadData(validPath).isvalid());
}
#Test
void testInvalidBuy() {
assertFalse(reader.loadData(invalidPath).isValid());
}
I realise I've simplified it a bit but hopefully you get the idea.
I'm developing an application where I would like to create a compiled and defined custom text-protocol. I.e. I want to send textstrings that represent information / actions to take in a server-client based system.
Is there any reference / best practice way to do this object oriented (in java)?
Some examples of the actual text strings that might be sent, for convenience separated with spaces (will be split by something else in the real case):
command1 <timestamp> <id> <arg1> <arg2>
command2 <timestamp> <id> <arg1> <arg2> <arg3>
command3 subcommand1 <timestamp> <id>
command3 subcommand2 <timestamp> <id>
So some things are included in all messages, but in other ways the messages could be totally different, depending on future implementations and so on.
What I would like to achieve with this is that the received textstring should be parsed with this protocol so that the parties that use it only have to pass the received text string to the protocol and then be able to switch to different functionality depending on the message type. My first thought was if it was possible to implement a base class, let's say "Message", and then subclasses for more specific message types (example Register or UpdateSomething).
Pseudo code to explain roughly what I wanted to achieve:
object msg = new Message(rawText);
switch (msg.getType()) {
case Message.Register:
// Register logic, data needed would be available in the msg-object.
// Most likely a function, for instance: handleRegistration(msg.uid, msg.password)
break;
case Message.SomeData.Get:
// logic/function to return SomeData, args/data needed would be available in the msg-object.
break;
case Message.SomeData.Update:
// logic/function to update SomeData, args/data needed would be available in the msg-object.
break;
default:
// Some default logic.
break;
But I realized that even if I was able to parse the rawText and somehow transform it into different objects depending on its contents (How can I do this?), it wouldn't be possible to switch on object type in a nice way and I've seen that many argue that it isn't a good approach.
I can get all this to work in lots of ugly ways, that's no problem, I'm just very unsure about the correct approach to this. I'd really like to learn how to do this in a nice and usable way also considering scaling (the protocol will grow). I want the protocol to just be a package (jar) that each party (different clients and the server) can use after which no one needs to bother with what (text) is actually sent over the connection.
Any help and guidance is greatly appreciated, I'm open to take other completely different paths. Do note again however that I'm not asking for help to just "get it working". I'm asking about the best practice(s) to implement those things, or references where I and others reading this can learn how to do this.
Thanks!
EDIT:
I guess the main problem I have is the problem itself. The messages differ quite a bit from each other, meaning I will end up in quite a few classes if I want the data members to be unique. This in itself isn't really a problem, it's just the names have to be unique as well. I'd like to group them up in some hierarchy.
For example with the REGISTER type:
A REGISTER message is a type of MESSAGE. But there are also different kinds of register messages:
REGISTER REQUEST <id> <password>
REGISTER OK
REGISTER ERROR <reason>
I would like to group these up in the sense that they are all register messages, but they are also different types of register messages with different payloads (ie need a different set of members if translated to objects). So if I'd like an object to be able to extract this information from variables I'd need 3 classes for this (example RegisterRequestMessage, RegisterOKMessage, RegisterErrorMessage) and it just feels as if all those classes and names could get a bit too much.
I wish to achieve:
Readability and usability for the developer using the protocol, when
they make their switch case to see which message they received or
when they make a new message they should easily (in a IDE that
supports it) be able to list the message-types they can choose from.
Be able to extract information from a message that is unique for
different message-types depending on what is being sent. I'd like the
data available to such a message to be visible (again in a IDE that
supports it) when the object is being used.
I guess there won't be any real smooth way here, either I'll end up with lots of classes (the problem is really lots of long names for messagtypes/classes), or I'll end up having to make it more generic, filling up a json-object or similar with the data.
Lots of classes:
handleRegisterMessage(MyLongNameSpecifiedMessageClass msg) {
this.id = msg.id;
this.password = msg.password;
// etc etc
}
More generic json or such:
handleRegisterMessage(JSONObject msg) {
this.id = msg.get("id");
this.password = msg.get("password");
// etc etc
}
I'm not sure if there's much more to do, but if you guys with more experience see some more elegant or easier solution here that I don't I'm happy to try it out.
EDIT 2:
Decided to use a unique class for each message type, even though there will be quite a few messages and the names might get somewhat long / ugly It felt like the most encapsulated and easy-to-use way. It will be compiled into a jar file and used that way anyways. Thanks for all suggestions though since other people might decide to take other paths.
If I understand what you mean, basically, a message is something that must
be parsed from a string,
be used to do something.
So, you could have something like
abstract class Message {
public abstract void doSomething();
private String myType; // or enum, or whatever
public String getMyType() {
return myType;
}
public static Message parse(String s) {
// parse s
// if s contains command 'register', return a new RegisterMessage
// if s contains command 'someDataGet', return a new SomeDataGetMessage
return // a newly created message;
}
}
class MessageRegister extends Message {
#Override
public void doSomething() {
// do what a Register message does
}
public MessageRegister() {
myType = "REGISTER";
}
}
class MessageSomeDataGet extends Message {
#Override
public void doSomething() {
// do what a SomeDataGet message does
}
public MessageSomeDataGet() {
myType = "SOMEDATAGET";
}
}
Then, you create a new message with
Message m = Message.parse("some command");
You can switch on the message type like this:
switch (m.getMyType()) {
case "SOMEDATAGET":
// whatever
}
The way I usually do this is with an interface, lets call it ConsoleProgram that takes string arguments and a HashMap that couples a string to a Program. Basically doing something similar to your switch statement and then each Program can worry about its own format when its passed the rest of the string (excluding the first program selecting part of the string)
public interface ConsoleProgram {
public String getProgramName(); //what the command string starts with to call this program
public void runProgram(String[] arguments);
}
Then a single class can deal with recieving strings and passing them to ConsolePrograms without ever worrying about what the ConsoleProgram actually does
public class Console{
public static HashMap<String, ConsoleProgram> availablePrograms=new HashMap<>();
public void registerProgram(ConsoleProgram program){
availablePrograms.put(program.getProgramName().toLowerCase(), program);
}
public void recieveCommand(String command){
String[] parts = command.split(" ");
ConsoleProgram program=availablePrograms.get(parts[0].toLowerCase());
if (program!=null){
System.out.println(
program.runProgram(Arrays.copyOfRange(parts, 1, parts.length));
}else{
System.out.println("program unavailable");
System.out.println(
availablePrograms.get("availableprograms").runProgram(parts, this, null)
);
}
}
}
This is something I myself use to support administrative functions within a game I am developing and it scales very nicely. Furthermore if a ConsoleProgram needs access to unusual things you don't need to have Console know about them, the specific ConsoleProgram can take those objects in its constructor before being registered using registerProgram
Instead of writing your own serializers/parcers I recommend using one of well-known tools that are created exactly for that.
One of my favourites is protocol buffers from google and there are many others.
With protocol buffers you would need to define your custom message formats (look at their simple java tutorial for reference), and then generate java code for it.
You would do it on both server/client sides, or, I guess you could simply include generated files along with dependency jar in your library and share it between server/clients.
This will have number of benefits :
You won't need to write your serializer/parser (and more importantly spend time debugging it!)
It is flexible, you can change/extend your messages in future
You are not limited to Java implementations, same message format can be understood by other servers/clients written in C++/Python.
In Java, it is possible to get the class and method that called the current method (the method in which you get the StackTrace).
Can I get the arguments that were passed to the method that called this method?
I need this for debugging purposes.
Eg:
baseClass {
initialFunc(input) {
var modifiedInput = input + " I modified you";
otherClass.doSomething(modifiedInput);
}
}
otherClass {
doSomething(input) {
//GET THE ARGUMENTS PASSED TO THE METHOD OF THE CLASS THAT CALLED THIS METHOD
}
}
Can one get this information from the stacktrace, or are there other means?
(Note that I need to be able to do this in runtime and cannot actually change the source of baseClass, this is going to be a feature of my debugging class that does not know the source beforehand)
I don't believe this is possible using the standard Java API.
What you could do is to use AspectJ, place a point-cut at the calling method, save the arguments, place a point-cut at the called method and pass on the arguments.
Another option (slightly more advanced) is to use a custom, bytecode-rewriting, class loader that saves the original arguments, and passes them on as extra arguments to the next method. This would probably take a day or two to implement. Suitable frameworks are BCEL or ASM.
I think this could be possible, because input is out of scope but isn't yet accessible for garbage collection, so the value still exists, but unfortunately I don't believe there is an default API way to access it. This could be maybe possible with a custom implemented NDC (nested diagnostic context) for the logging approach.
I'm not sure why you'd ever want to do this in Java?
The only way I can think of is to create a custom wrapper object for the passed string, thus sending the reference to the wrapper instead of a new string each time.
I'd advice against it, though, since it clutters your original code, and makes it even more error prone.
Might this problem not be solved using a debugger, like the one built into eclipse, to inspect your state?
In my case, I needed to get a parameter value has been passed to a method in a certain stack frame to be used later within the execution flow
I used ThreadLocal to store it and when I needed it I was able to retrieve it at any point in code as I declared it as public static
here is a skeleton example
public static final ThreadLocal<SomeType> IMPORTANT_THREAD_LOCAL_FOR_BLA = ThreadLocal.withInitial(whatever);
methodWithImportantParam(SomeType importantValue){
// save it in the static threadLocal Field
this.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()=importantValue;// code to set the value
// continue method logic
}
and somewhere in code where you need that value
YourClass.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()
but make sure the execution flow that you set the value then you retrieve it
hope my answer add something valuable to this question
You can get name of caller method and its class, but you have to add some code in current method:
public static void main(String[] args) throws Exception {
call();
}
private static void call() {
Exception exception = new Exception();
for(StackTraceElement trace : exception.getStackTrace()){
System.out.println(trace.getMethodName());
}
}
This will print "call" and "main", methods name in called order (reverse).
This is possible using Reflection API !
public class StackTrace {
public static void main(String args[]) {
StackTrace st = new StackTrace();
st.func();
}
public void func() {
OtherClass os =new OtherClass();
os.getStackTrace(this);
}
}
class OtherClass {
void getStackTrace(Object obj) {
System.out.println(obj.getClass());
}
}
My question is based around invoking a server method by using the command pattern. However there are many possible commands. I would like to introduce a return type for the 'execute' method of each command instance. I know this is not the intended use of the command pattern, but I haven't any other choice. I need to tailor the command pattern to work for me.
For the method signature of the 'execute' method in each command, what could I possibly have as the return type? I'm guessing it would have to be a covariant return type. It's not an ideal solution but I haven't many other options. I'm developing a server for my android app and RMI isn't available in the Android SDK. I would appreciate any advice about the return type issue. I would need to take account of all of the return types that could be returned from all of the different commands. I'm not sure if there is a pattern out there for this issue of returning some sort of generic return type.
I have already looked at this thread:
command pattern returning status
but I need more inspiration.
I probably don't understand the real question here, but this sounds straightforward.
public interface Command<T> {
T execute();
}
And then teh commands could be:
public class FooCommand implements Command<Bar> {
public Bar execute() {
...
}
}
Or is there a catch somewhere?
It looks like what you really want is RMI, which Android doesn't support.
You can try to use a lightweight RMI.
To implement something yourself, start from biziclop's interface,
// suppose there are object input/output streams established
// on client side
FooCommand foo = new FooCommand(params..);
Bar bar = remoteExec( foo );
<T> T remoteExec(Command<T> cmd)
output.writeObject(cmd);
return (T)input.readObject();
// on server side
Command cmd = (Command)input.readObject();
Object result = cmd.execute();
output.writeObject(result);
There's something very unsatisfactory about this code:
/*
Given a command string in which the first 8 characters are the command name
padded on the right with whitespace, construct the appropriate kind of
Command object.
*/
public class CommandFactory {
public Command getCommand(String cmd) {
cmdName = cmd.subString(0,8).trim();
if(cmdName.equals("START")) {
return new StartCommand(cmd);
}
if(cmdName.equals("END")) {
return new EndCommand(cmd);
}
// ... more commands in more if blocks here
// else it's a bad command.
return new InvalidCommand(cmd);
}
}
I'm unrepentant about the multiple exit points - the structure is clear. But I'm not happy about the series of near-identical if statements. I've considered making a Map of Strings to Commands:
commandMap = new HashMap();
commandMap.put("START",StartCommand.class);
// ... etc.
... then using Reflection to make instances of the appropriate class looked up from the Map. However while conceptually elegant, this involves a fair amount of Reflection code that whoever inherits this code might not appreciate - although that cost might be offset by the benefits. All the lines hardcoding values into the commandMap smell almost as bad as the if block.
Even better would be if the factory's constructor could scan the classpath for subclasses of Command, query them for String representations, and automatically add them them to its repertoire.
So - how should I go about refactoring this?
I guess some of the frameworks out there give me this kind of thing for free. Let's assume I'm not in a position to migrate this stuff into such a framework.
How about the following code:
public enum CommandFactory {
START {
#Override
Command create(String cmd) {
return new StartCommand(cmd);
}
},
END {
#Override
Command create(String cmd) {
return new EndCommand(cmd);
}
};
abstract Command create(String cmd);
public static Command getCommand(String cmd) {
String cmdName = cmd.substring(0, 8).trim();
CommandFactory factory;
try {
factory = valueOf(cmdName);
}
catch (IllegalArgumentException e) {
return new InvalidCommand(cmd);
}
return factory.create(cmd);
}
}
The valueOf(String) of the enum is used to find the correct factory method. If the factory doesn't exist it will throw an IllegalArgumentException. We can use this as a signal to create the InvalidCommand object.
An extra benefit is that if you can make the method create(String cmd) public if you would also make this way of constructing a Command object compile time checked available to the rest of your code. You could then use CommandFactory.START.create(String cmd) to create a Command object.
The last benefit is that you can easily create a list of all available command in your Javadoc documentation.
Your map of strings to commands I think is good. You could even factor out the string command name to the constructor (i.e. shouldn't StartCommand know that its command is "START"?) If you could do this, instantiation of your command objects is much simpler:
Class c = commandMap.get(cmdName);
if (c != null)
return c.newInstance();
else
throw new IllegalArgumentException(cmdName + " is not as valid command");
Another option is to create an enum of all your commands with links to the classes (assume all your command objects implement CommandInterface):
public enum Command
{
START(StartCommand.class),
END(EndCommand.class);
private Class<? extends CommandInterface> mappedClass;
private Command(Class<? extends CommandInterface> c) { mappedClass = c; }
public CommandInterface getInstance()
{
return mappedClass.newInstance();
}
}
since the toString of an enum is its name, you can use EnumSet to locate the right object and get the class from within.
With the exception of the
cmd.subString(0,8).trim();
part, this doesn't look too bad to me. You could go with the Map and use reflection, but, depending on how often you add/change commands, this might not buy you much.
You should probably document why you only want the first 8 characters, or maybe change the protocol so it's easier to figure out which part of that string is the command (e.g. put a marker like ':' or ';' after the command key-word).
Its not directly an answer to your question, but why don't you throw an InvalidCommandException (or something similar), rather then returning an object of type InvalidCommand?
Unless there is a reason they can't be I always try to make my command implementations stateless. If that's the case you can add a method boolean identifier(String id) method to your command interface which would tell whether this instance could be used for the given string identifier. Then your factory could look something like this (note: I did not compile or test this):
public class CommandFactory {
private static List<Command> commands = new ArrayList<Command>();
public static void registerCommand(Command cmd) {
commands.add(cmd);
}
public Command getCommand(String cmd) {
for(Command instance : commands) {
if(instance.identifier(cmd)) {
return cmd;
}
}
throw new CommandNotRegisteredException(cmd);
}
}
I like your idea, but if you want to avoid reflection you could add instead instances to the HashMap:
commandMap = new HashMap();
commandMap.put("START",new StartCommand());
Whenever you need a command, you just clone it:
command = ((Command) commandMap.get(cmdName)).clone();
And afterwards, you set the command string:
command.setCommandString(cmdName);
But using clone() doesn't sound as elegant as using reflection :(
Taking a Convetion vs Configuration approach and using reflection to scan for available Command objects and loading them into your map would be the way to go. You then have the ability to expose new Commands without a recompile of the factory.
Another approach to dynamically finding the class to load, would be to omit the explicit map, and just try to build the class name from the command string. A title case and concatenate algorithm could turn "START" -> "com.mypackage.commands.StartCommand", and just use reflection to try to instantiate it. Fail somehow (InvalidCommand instance or an Exception of your own) if you can't find the class.
Then you add commands just by adding one object and start using it.
One option would be for each command type to have its own factory. This gives you two advantages:
1) Your generic factory wouldn't call new. So each command type could in future return an object of a different class according to the arguments following the space padding in the string.
2) In your HashMap scheme, you could avoid reflection by, for each command class, mapping to an object implementing a SpecialisedCommandFactory interface, instead of mapping to the class itself. This object in practice would probably be a singleton, but need not be specified as such. Your generic getCommand then calls the specialised getCommand.
That said, factory proliferation can get out of hand, and the code you have is the simplest thing that does the job. Personally I'd probably leave it as it is: you can compare command lists in source and spec without non-local considerations like what might have previously called CommandFactory.registerCommand, or what classes have been discovered through reflection. It's not confusing. It's very unlikely to be slow for less than a thousand commands. The only problem is that you can't add new command types without modifying the factory. But the modification you'd make is simple and repetitive, and if you forget to make it you get an obvious error for command lines containing the new type, so it's not onerous.
Having this repetitive object creation code all hidden in the factory is not so bad. If it has to be done somewhere, at least it's all here, so I'd not worry about it too much.
If you really want to do something about it, maybe go for the Map, but configure it from a properties file, and build the map from that props file.
Without going the classpath discovery route (about which I don't know), you'll always be modifying 2 places: writing a class, and then adding a mapping somewhere (factory, map init, or properties file).
Thinking about this, You could create little instantiation classes, like:
class CreateStartCommands implements CommandCreator {
public bool is_fitting_commandstring(String identifier) {
return identifier == "START"
}
public Startcommand create_instance(cmd) {
return StartCommand(cmd);
}
}
Of course, this adds a whole bunch if tiny classes that can't do much more than say "yes, thats start, give me that" or "nope, don't like that", however, you can now rework the factory to contain a list of those CommandCreators and just ask each of it: "you like this command?" and return the result of create_instance of the first accepting CommandCreator. Of course it now looks kind of akward to extract the first 8 characters outside of the CommandCreator, so I would rework that so you pass the entire command string into the CommandCreator.
I think I applied some "Replace switch with polymorphism"-Refactoring here, in case anyone wonders about that.
I'd go for the map and creation via reflection. If scanning the class path is too slow, you can always add a custom annotation to the class, have an annotation processor running at compile time and store all class names in the jar metadata.
Then, the only mistake you can do is forgetting the annotation.
I did something like this a while ago, using maven and APT.
The way I do it is to not have a generic Factory method.
I like to use Domain Objects as my command objects. Since I use Spring MVC this is a great approach since the DataBinder.setAllowedFields method allows me a great deal of flexibility to use a single domain object for several different forms.
To get a command object, I have a static factory method on the Domain object class. For example, in the member class I'd have methods like -
public static Member getCommandObjectForRegistration();
public static Member getCommandObjectForChangePassword();
And so on.
I'm not sure that this is a great approach, I never saw it suggested anywhere and kind of just came up with it on my own b/c I like the idea of keeping things like this in one place. If anybody sees any reason to object please let me know in the comments...
I would suggest avoiding reflection if at all possible. It is somewhat evil.
You can make your code more concise by using the ternary operator:
return
cmdName.equals("START") ? new StartCommand (cmd) :
cmdName.equals("END" ) ? new EndCommand (cmd) :
new InvalidCommand(cmd);
You could introduce an enum. Making each enum constant a factory is verbose and also has some runtime memory cost. But you can eaily lookup an enum and then use that with == or switch.
import xx.example.Command.*;
Command command = Command.valueOf(commandStr);
return
command == START ? new StartCommand (commandLine) :
command == END ? new EndCommand (commandLine) :
new InvalidCommand(commandLine);
Go with your gut, and reflect. However, in this solution, your Command interface is now assumed to have the setCommandString(String s) method accessible, so that newInstance is easily useable. Also, commandMap is any map with String keys (cmd) to Command class instances that they correspond to.
public class CommandFactory {
public Command getCommand(String cmd) {
if(cmd == null) {
return new InvalidCommand(cmd);
}
Class commandClass = (Class) commandMap.get(cmd);
if(commandClass == null) {
return new InvalidCommand(cmd);
}
try {
Command newCommand = (Command) commandClass.newInstance();
newCommand.setCommandString(cmd);
return newCommand;
}
catch(Exception e) {
return new InvalidCommand(cmd);
}
}
Hmm, browsing, and only just came across this. Can I still comment?
IMHO there's nothing wrong with the original if/else block code. This is simple, and simplicity must always be our first call in design (http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork)
This seems esp true as all the solutions offered are much less self documenting than the original code...I mean shouldn't we write our code for reading rather than translation...
At the very least, your command should have a getCommandString() -- where StartCommand overrides to return "START". Then you can just register or discover the classes.
+1 on the reflection suggestion, it will give you a more sane structure in your class.
Actually you could do the following (if you haven't thought about it already)
create methods corresponding to the String you'd be expecting as an argument to your getCommand() factory method, then all you have to do is reflect and invoke() these methods and return the correct object.