I want to make a simple interative shell based on the console where I can write commands like login, help, et cetera.
I first thought of using Enums, but then I didn't know how to implement them neatly without a load of if-else statements, so I decided to go with an array-approach and came up with this:
public class Parser {
private static String[] opts = new String[] {"opt0", "opt1", "opt2", "opt3" ... }
public void parse(String text) {
for(int i = 0; i < opts.length; i++) {
if(text.matches(opts[i]) {
switch(i) {
case 0:
// Do something
case 1:
// Do something-something
case 2:
// Do something else
}
return;
}
}
}
}
But I ended up seeing that this was probably the most rudimentary way of doing something like this, and that there would be problems if I wanted to change the order of the options. How could I make a simpler parser? This way it would work, but it would also have said problems. The use of the program is purely educational, not intended for any serious thing.
A simple approach is to have a HashMap with the key equal to the command text and the value is an instance of class that handle this command. Assuming that the command handler class does not take arguments (but you can easily extend this) you can just use a Runnable instance.
Example code:
Runnable helpHandler = new Runnable() {
public void run(){
// handle the command
}
}
// Define all your command handlers
HashMap<String, Runnable> commandsMap = new HashMap<>(); // Java 7 syntax
commandsMap.put("help",helpHandler);
// Add all your command handlers instances
String cmd; // read the user input
Runnable handler;
if((handler = commandsMap.get(cmd)) != null) {
handler.run();
}
You can easily extend this approach to accept argument by implementing your own interface and subclass it. It is good to use variable arguments if you know the data type e.g. void execute(String ... args)
One solution that comes to mind is actually using Design patterns. You could use the input from the user, as the discriminator for a Factory class.
This factory class will generate an object, with an "execute" method, based on the input. This is called a Command object.
Then you can simply call the method of the object returned from the factory.
No need for a switch statement. If the object is null, then you know the user entered an invalid option, and it abstracts the decision logic away from your input parser.
Hopefully this will help :)
Related
I need to write a custom LemmaTokenFilter, which replaces and indexes the words with their lemmatized(base) form. The problem is, that I get the base forms from an external API, meaning I need to call the API, send my text, parse the response and send it as a Map<String, String> to my LemmaTokenFilter. The map contains pairs of <originalWord, baseFormOfWord>. However, I cannot figure out how can I access the full value of the text field, which is being proccessed by the TokenFilters.
One idea is to go through the tokenStream one by one when the LemmaTokenFilter is being created by the LemmaTokenFilterFactory, however I would need to watch out to not edit anything in the tokenStream, somehow reset the current token(since I would need to call the .increment() method on it to get all the tokens), but most importantly this seems unnecessary, since the field value is already there somewhere and I don't want to spend time trying to put it together again from the tokens. This implementation would probably be too slow.
Another idea would be to just process every token separately, however calling an external API with only one word and then parsing the response is definitely too inefficient.
I have found something on using the ResourceLoaderAware interface, however I don't really understand how could I use this to my advantage. I could probably save the map in a text file before every indexing, but writing to a file, opening it and reading from it before every document indexing seems too slow as well.
So the best way would be to just pass the value of the field as a String to the constructor of LemmaTokenFilter, however I don't know how to access it from the create() method of the LemmaTokenFilterFactory.
I could not find any help googling it, so any ideas are welcome.
Here's what I have so far:
public final class LemmaTokenFilter extends TokenFilter {
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
private Map<String, String> lemmaMap;
protected LemmaTokenFilter(TokenStream input, Map<String, String> lemmaMap) {
super(input);
this.lemmaMap = lemmaMap;
}
#Override
public boolean incrementToken() throws IOException {
if (input.incrementToken()) {
String term = termAtt.toString();
String lemma;
if ((lemma = lemmaMap.get(term)) != null) {
termAtt.setEmpty();
termAtt.copyBuffer(lemma.toCharArray(), 0, lemma.length());
}
return true;
} else {
return false;
}
}
}
public class LemmaTokenFilterFactory extends TokenFilterFactory implements ResourceLoaderAware {
public LemmaTokenFilterFactory(Map<String, String> args) {
super(args);
if (!args.isEmpty()) {
throw new IllegalArgumentException("Unknown parameters: " + args);
}
}
#Override
public TokenStream create(TokenStream input) {
return new LemmaTokenFilter(input, getLemmaMap(getFieldValue(input)));
}
private String getFieldValue(TokenStream input) {
//TODO: how?
return "Šach je desková hra pro dva hráče, v dnešní soutěžní podobě zároveň považovaná i za odvětví sportu.";
}
private Map<String, String> getLemmaMap(String data) {
return UdPipeService.getLemma(data);
}
#Override
public void inform(ResourceLoader loader) throws IOException {
}
}
1. API based approach:
You can create an Analysis Chain with the Custom lemmatizer on top. To design this lemmatizer, I guess you can look at the implementation of the Keyword Tokenizer;
Such that you can read everything whatever is there inside the input and then call your API;
Replace all your tokens from the API response in the input text;
After that in Analysis Chain, use standard or white space tokenizer to tokenized your data.
2. File-Based Approach
It will follow all the same steps, except calling the API it can use the hashmap, from the files mentioned while defining the TokenStream
Now coming to the ResourceLoaderAware:
It is required when you need to indicate your Tokenstream that resource has changed it has inform method which takes care of that. For reference, you can look into StemmerOverrideFilter
Keyword Tokenizer: Emits the entire input as a single token.
So I think I found the answer, or actually two answers.
One would be to write my client application in a way, that incoming requests are first processed - the field value is sent to the external API and the response is stored into some global variable, which can then be accessed from the custom TokenFilters.
Another one would be to use custom UpdateRequestProcessors, which allow us to modify the content of the incoming document, calling the external API and again saving the response so it's somehow globally accessible from custom TokenFilters. Here Erik Hatcher talks about the use of the ScriptUpdateProcessor, which I believe can be used in my case too.
Hope this helps to anyone stumbling upon a similar problem, because I had a hard time looking for a solution to this(could not find any similar threads on SO)
Let's say I'm writing a bot for a chat (discord, telegram, whatever). The bot can handle chat commands (e.g. !join tells it to join a voice channel on the server).
So somewhere in my code I'd have to parse the command, and I'll have something like
String userMessage = getTheMessageTextSomehow();
// Do something with the message.
I'd like to have a Command class for every one of my commands, and every command would implement a execute() method.
My question is: what's the best practice to create those command objects?
The easiest way would be to have a large CommandFactory or whatever class somwhere, that would be like
if(message.equals(JOIN_MESSAGE) {
return new JoinCommand();
}
if(message.equals(LEAVE_MESSAGE){
return new LeaveCommand();
}
//etc...
That looks like a bad practice and code smell to me.
Is there a better way to do it?
You might want to rely on a Map of Commands.
I'll make it clear that for this usecase, using the Function or Supplier, or whatever standard functional interface is not idiomatic at all. Avoid it.
We can start by building a Command interface
interface Command {
Result execute();
}
Or if you need to accept an argument
interface Command {
Result execute(final Input input);
}
Which will have the required implementations
class JoinCommand implements Command { ... }
class LeaveCommand implements Command { ... }
class NoopCommand implements Command { ... }
And so on.
You'll now need to store those definitions in a key (the command) - value (the implementation) data structure. A Map is perfect for that.
As your command definition will be a String, then
static final Map<String, Command> COMMANDS = new HashMap<>(8);
static {
COMMANDS.put("join", new JoinCommand());
COMMANDS.put("leave", new LeaveCommand());
// And so on
}
The usage is pretty simple
final String userMessage = getTheMessageTextSomehow();
final String commandStr = extractCommand(userMessage);
final Command command = COMMANDS.getOrDefault(commandStr, NOOP_COMMAND);
command.execute();
Or if you'll have to accept an argument
command.execute(yourInput);
You'll also notice I used NOOP_COMMAND, that's just a no-op implementation for Command to avoid dealing with null. It might be, or it might be not, appropriate.
If you're on Java 9+, the Map could also be created using
Map.of(
"join", new JoinCommand(),
"leave", new LeaveCommand(),
// And so on.
)
Usually, it is implemented via mapping. It would be much clearer and readable to implement this with simple Map.
For example:
Map<String, Command> strategies = new HashMap<String, Command>(){{
put(JOIN_MESSAGE, new JoinCommand());
put(LEAVE_MESSAGE, new LeaveCommand());
}};
And its usage:
Command command = strategies.get(messageType);
Moreover, you can define creation strategies (factories) since Java 8 if you need to construct commands depending on some parameters.
Map<String, Function<String, Command>> strategies = new HashMap<String, Command>(){{
put(JOIN_MESSAGE, param -> new JoinCommand(param)); // or JoinCommand::new
put(LEAVE_MESSAGE, param -> new LeaveCommand(param)); // or LeaveCommand::new
}};
And its usage:
Command command = strategies.get(messageType);
command.process(param);
Hello You try Switch Case statement for it, it's easy to understand and in future if you have any changes then it's easy to update the code.
switch(message)
{
case JOIN_MESSAGE:
return new JoinCommand();
break;
case LEAVE_MESSAGE:
return new LeaveCommand();
break;
}
I am making a multiplayer game which makes heavy use of a serialisable Event class to send messages over a network. I want to be able to reconstruct the appropriate subclass of Event based on a constant.
So far I have opted for the following solution:
public class EventFactory {
public static Event getEvent(int eventId, ByteBuffer buf) {
switch (eventId){
case Event.ID_A:
return EventA.deserialise(buf);
case Event.ID_B:
return EventB.deserialise(buf);
case Event.ID_C:
return EventC.deserialise(buf);
default:
// Unknown Event ID
return null;
}
}
}
However, this strikes me as being very verbose and involves adding a new 'case' statement every time I create a new Event type.
I am aware of 2 other ways of accomplishing this, but neither seems better*:
Create a mapping of constants -> Event subclasses, and use clazz.newInstance() to instantiate them (using an empty constructor), followed by clazz.initialiase(buf) to supply the necessary parameters.
Create a mapping of constants -> Event subclasses, and use reflection to find and call the right method in the appropriate class.
Is there a better approach than the one I am using? Am I perhaps unwise to disregard the alternatives mentioned above?
*NOTE: in this case better means simpler / cleaner but without compromising too much on speed.
You can just use a HashMap<Integer,Event> to get the correct Event for the eventID. Adding or removing events is going to be easy, and as the code grows this is easy to maintain when compared to switch case solution and speed wise also this should be faster than switch case solution.
static
{
HashMap<Integer,Event> eventHandlerMap = new HashMap<>();
eventHandlerMap.put(eventId_A, new EventHandlerA());
eventHandlerMap.put(eventId_B, new EventHandlerB());
............
}
Instead of your switch statement Now you can just use :
Event event = eventHandlerMap.get(eventId);
if(event!=null){
event.deserialise(buf);
}
If you're not afraid of reflection, you could use:
private static final Map<Integer, Method> EVENTID_METHOD_MAP = new LinkedHashMap<>();
static {
try {
for (Field field : Event.class.getFields())
if (field.getName().startsWith("ID_")) {
String classSuffix = field.getName().substring(3);
Class<?> cls = Class.forName("Event" + classSuffix);
Method method = cls.getMethod("deserialize", ByteBuffer.class);
EVENTID_METHOD_MAP.put(field.getInt(null), method);
}
} catch (IllegalAccessException|ClassNotFoundException|NoSuchMethodException e) {
throw new ExceptionInInitializerError(e);
}
}
public static Event getEvent(int eventId, ByteBuffer buf)
throws InvocationTargetException, IllegalAccessException {
return (Event) EVENTID_METHOD_MAP.get(eventId).invoke(null, buf);
}
This solution requires that int ID_N always maps to class EventN, where N can be any String where all characters return true for the method java.lang.Character.isJavaIdentifierPart(c). Also, class EventN must define a static method called deserialize with one ByteBuffer argument that returns an Event.
You could also check if field is static before trying to get its field value. I just forget how to do that at the moment.
I'm writing a program that needs to have Command Objects. A Command contains a String for its name, and an AbstractAction that represents what the Command actually does. Furthermore, a Command has a method, init(), used higher up in the program's hierarchy that instantiates variables for the Command's use (to provide access to the GUI, network, and so on), and a method, execute(), that executes the AbstractAction on a special Thread. Here is an example of creating and using a Command:
Command c = new Command("Test",
new AbstractAction() {
public void actionPerformed(ActionEvent a) {
System.out.println("Hello world!");
}
});
At this point, calling "c.execute();" will print out "Hello world!", as expected.
My goal is to have a text file with pairs of values, which can be parsed to generate a String name and an AbstractAction action. Once that has been done, another class will go through the found names and actions, create Command Objects for each one, and add them to the list of commands in the program, where they can then be used as normal.
Right now, my problem is that I read in a String that represents the body of the private AbstractAction above- but there isn't an easy way to actually convert the String into an actual AbstractAction Object.
One potential idea was creating a temporary java file with the AbstractAction String representation, compiling it, creating a new AbstractAction from it, and then get that reference using reflection, but that seems like overkill. Another was to directly modify the source of the file that parses through the file, so that it would have the code of the AbstractAction written out, but again, this is a bit crazy.
I've tried a few other implementations, including forcing the user to create a subclass of Command, putting their source into a special program folder, and then creating the Commands on initialisation, but this ended up being a lot of work for the user (lots of redundant code).
Please let me know if there's a better way to implement what I want to do- or if there's an easier way to turn the String of the source into an inner Object as above.
Edit 1:
Here is an example of what the text file would look like:
//Anything outside of quotes is a comment
"Foo", "System.out.println("Hello world!");"
"Bar", "network.sendOverAFile(new File("test.txt"));"
From here, the parser (on startup) would read through the file and extract "Foo" as a String name, and "System ... ;" as a String action. I need to turn action into the code in the body of the AbstractAction, as seen above when creating the Command.
The same would be done for Bar; Bar uses one of the variables passed by init().
As for the subclass implementation I tried, the user would have to create their own subclass of Command, and put it into a source folder. A subclass would look something like this:
public class TestCommand extends Command {
public TestCommand() {
super("Test", new AbstractAction() {
public void actionPerformed(ActionEvent a) {
System.out.println("Hello!");
}
});
}
}
This would then be put into a source directory, among every other subclassed Command, and compiled. The parser would go through the compiled code segments, and add the relevant information to an array. Every time a Command would normally be executed, the parser scans through the list of all names, and if there is a match, execute the relevant AbstractAction. This works, but involves a ton of references to external classes (which will probably slow down the program with dozens of commands), and is two or three times as much work for the users making the plugin. As a result, I felt it would be much easier to use the text file technique above, but I don't know how to turn a String representation of the code into the code itself; Ergo my initial question.
This sounds like a case of overengineering. Do you really need this much flexibility at runtime, or do you simply have a lot of commands and you want an easy way to refer to them in a file?
If it's the latter, your text file doesn't need to contain the code; it just needs to contain symbolic identifiers corresponding to that code. Those identifiers should exist in your code as enum constants:
public enum Command { FOO, BAR }
You should create all of your actions in code, and place those actions in a Map using the enum constants as keys. Your file can then refer to the actions by those enum constants:
public List<Action> parseActions(Path file)
throws IOException {
List<Action> actions = new ArrayList<>();
try (BufferedReader reader =
Files.newBufferedReader(file, Charset.defaultCharset())) {
String line;
while ((line = reader.readLine()) != null) {
Command command = Command.valueOf(line);
Action action = getAction(command);
actions.add(action);
}
}
return actions;
}
private Map<Command, Action> allActions;
private Action getAction(Command command) {
Objects.requireNonNull(command, "Command cannot be null");
if (allActions == null) {
allActions = new EnumMap<>(Command.class);
allActions.put(Command.FOO, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
System.out.println("Hello world!");
}
};
allActions.put(Command.BAR, new AbstractAction() {
public void actionPerformed(ActionEvent event) {
network.sendOverAFile(new File("test.txt"));
}
};
// Safety check
if (!allActions.keySet().containsAll(
EnumSet.allOf(Command.class))) {
throw new RuntimeException(
"Not every Command constant has an associated Action");
}
}
return allActions.get(command);
}
To conform to the above, your text file would simply contain:
FOO
BAR
If you really and truly need fully dynamic code that can be read from a text file, bear in mind that it is a tremendous security hole. In fact, it is the very definition of code injection: anyone can place arbitrary code (including things like Runtime.getRuntime().exec("rd /s/q C:\\Windows\\System32") or Runtime.getRuntime().exec("rm -rf ~")) in a file and your program will gladly run it.
If you're still sure that you want to do it, you'd probably want to use the JavaScript engine that comes with every Java runtime:
public List<Action> parseActions(Path file)
throws IOException {
List<Action> actions = new ArrayList<>();
final ScriptEngine engine =
new ScriptEngineManager().getEngineByName("JavaScript");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("network", myNetwork);
try (BufferedReader reader =
Files.newBufferedReader(file, Charset.defaultCharset())) {
String line;
while ((line = reader.readLine()) != null) {
String[] nameAndCode = line.split("\\s+", 2);
String name = nameAndCode[0];
final String code = nameAndCode[1];
Action action = new AbstractAction() {
public void actionPerformed(ActionEvent event) {
engine.eval(code);
}
};
actions.add(action);
}
}
return actions;
}
Each line in your file would contain a command name followed by JavaScript code. So it might look like this:
Foo importClass(java.lang.System); System.out.println('Hello world!');
Bar importClass(java.io.File); network.sendOverAFile(new File('test.txt'));
Another major disadvantage of doing this, in my opinion, is that the code won't benefit from compiler checks, and you certainly can't set breakpoints in that code from a debugger. All in all, it will be a considerable headache to debug and maintain.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Long list of if statements in Java
I was tasked to work with some code, and there is a giant if-else-if chain (100+ else-ifs) that checks Strings.
What are some good techniques to update this code as to where the if-else-if chain can be shrunken down to something much more manageable.
The chain looks something like this:
if(name.equals("abc")){
do something
} else if(name.equals("xyz")){
do something different
} else if(name.equals("mno")){
do something different
} ......
.....
else{
error
}
You can extract the code in each branch to a separate method, then turn the methods into implementations of a common base interface (let's call it Handler). After that, you can fill a Map<String, Handler> and just look up and execute the right handler for given string.
Unfortunately the implementation of 100+ subclasses for the interface requires quite a lot of boilerplate code, but currently there is no simpler way in Java to achieve this. Implementing the cases as elements of an Enum may help somewhat - here is an example. The ideal solution would be using closures / lambdas, but alas we have to wait till Java 8 for that...
Some options / ideas:
Leave it as it is - it's not fundamentally broken, and is reasonably clear and simple to maintain
Use a switch statement (if you are using Java 7) - not sure if this gains you much though
Create a HashMap of String to FunctionObjects where the function objects implement the required behaviour as a method. Then your calling code is just: hashMap.get(name).doSomething();
Break it into a heirarchy of function calls by sub-grouping the strings. You could do this by taking each letter in turn, so one branch handles all the names starting with 'a' etc.
Refactor so that you don't pass the name as a String but instead pass a named object. Then you can just do namedObject.doSomething()
With Enums, you can have a method per instance.
public enum ActionEnum {
ABC {
#Override
void doSomething() {
System.out.println("Doing something for ABC");
}
},
XYZ {
#Override
void doSomething() {
System.out.println("Doing something for XYZ");
}
};
abstract void doSomething();
}
public class MyActionClass {
public void myMethod(String name) {
ActionEnum.valueOf("ABC").doSomething();
}
}
It is still kinda messy (big enum with 100+ entries, even it all it does is dispatching), but may avoid the HashMap initialization code (100+ puts is also messy in my opinion).
And yet another option (for documentation purposes) would be reflection:
public interface Action {
void doSomething();
}
public class ABCAction implements Action {
#Override
public void doSomething() {
System.out.println("Doing something for ABC");
}
}
public class MyActionClass {
void doSomethingWithReflection(String name) {
try {
Class<? extends Action> actionClass = Class.
forName("actpck."+ name + "Action").asSubclass(Action.class);
Action a = actionClass.newInstance();
a.doSomething();
} catch (Exception e) {
// TODO Catch exceptions individually and do something useful.
e.printStackTrace();
}
}
}
Each approach has it's trade offs:
HashMap = Fast + Kinda messy ("set-up" code with hundred of puts)
Enum = Fast + Kinda messy 2 (huge file).
Reflection = Slower + runtime error prone, but provides clean separation without resorting to clunky big HashMap.
Like Matt Ball said in his comment, you can use a command pattern. Define a collection of Runnable classes:
Runnable task1 = new Runnable() {
public void run() { /* do something */ }
};
Runnable task2 = // etc.
Then you can use a map from your keys to runnables:
Map<String,Runnable> taskMap = new HashMap<String,Runnable>();
taskMap.put("abc", task1);
taskMap.put("xyz", task2);
// etc.
Finally, replace the if-else chain with:
Runnable task = taskMap.get(name);
if (task != null) {
task.run();
} else {
// default else action from your original chain
}
you can use the switch statement , but Switch statements with String cases have been implemented in Java SE 7
the best solution is to use the command pattern
This is a popular Arrow Anti-Pattern and Jeff discusses some approaches to handle this very nicely in his post here.