I have the following code:
public void actionPerformed(ActionEvent e) {
String userInput = commandInput.getText();
if (currentLevel == 0) {
if (userInput.equals(answers.getIntroAnswers().get(0)) || userInput.equals(answers.getIntroAnswers().get(1))) {
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
getCurrentLevel();
} else {
messageDisplay.append(notValid());
}
} else if (currentLevel == 1) {
// do the same as above but with the next set of answers
}
}
What I'd like to do is somehow separate this action into it's own class and call the method /constructor within that class to do this checking else I will be stuck using nested if's and it will become very messy and hard to understand. Would I be right in thinking a method to take parameters of currentLevel and userInput in order to test the userInput against the corresponding answers based on the currentLevel? Below is a link to the rest of the classes involved:
https://github.com/addrum/TextGame.git
Would I be right in thinking a method to take parameters of currentLevel and userInput in order to test the userInput against the corresponding answers based on the currentLevel?
No. In fact, you probably want to avoid passing the current level as an explicit parameter. If you've got the level as a parameter, you will probably end up just pushing the "multiple nested ifs" into another class.
I think you need to write it like this:
InputChecker[] levelChecker = ... create an array of checker instances
....
levelChecker[currentLevel].check(userInput);
Then you need to create a class (possibly anonymous) to implement the checking for each level. Note that if you needed to you could supply the level number to a checker class via a constructor parameter and have it save it in a private instance variable.
You could expand/generalize the InputChecker interface to include other level-specific behaviour. Or indeed make this part of a Level interface.
"Is this taking the currentLevel and comparing the userInput to the current level?"
No. In my example code above it is calling a method on the InputChecker instance to do the checking. Since there are different InputChecker instances for each level, they can check different answers ... or whatever.
But if the only difference between the "input check" behaviours for each level is that they check against a different set of answers then:
levelAnswers = answers.getAnswersForLevel(currentLevel);
for (String answer : levelAnswers) {
if (userInput.equals(answer)) {
// blah blah blah
}
}
Why not create the method in the same class rather than having a different class to do that, considering other variables that method uses such as,
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
So I'd suggest creating the method in same then call it from actionPerformed
public void checks()
{
String userInput = commandInput.getText();
if (currentLevel == 0) {
if (userInput.equals(answers.getIntroAnswers().get(0)) || userInput.equals(answers.getIntroAnswers().get(1))) {
messageDisplay.append("\n \n" + userInput + "\n");
commandInput.setText("");
messageDisplay.append("\n" + messages.getNextMessage());
currentLevel++;
getCurrentLevel();
} else {
messageDisplay.append(notValid());
}
} else if (currentLevel == 1) {
// do the same as above but with the next set of answers
}
}
Then call it from actionPerformed
public void actionPerformed(ActionEvent e)
{
check():
}
So now you if's are handle in a seperate method.
To my eyes, since you are talking about levels so much, you probably should have a class that represents a level. Actually, since you obviously have more than one level, which acts slightly differently, you have two approaches.
Have a Level interface, and then make a class per level.
or
Have a Level class, with a constructor that hides the level number within the class.
After that, you can switch polymorphicly instead of nested if statements (or if's cousin, the switch statement).
Level level = currentLevel;
while (level != null) {
level.doStuff;
level = level.getNextLevel();
}
Related
public static void calculate(List<Person> data, String categoryType) {
for(int i = 0; i < categoryData.size(); i++) {
if(data.get(i).calculateCategoryOne() == firstPlace) {
...
}
}
}
If you see data.get(i).calculateCategoryOne(), the method call is for category one. The problem is that I need to copy-paste the entire code in a if-block for each category to just change this method call data.get(i).calculateCategoryTwo(), data.get(i).calculateCategoryThree(), ... data.get(i).calculateCategoryTen(),
While I can still make the logic work in this way, I feel it is redundant and not a good programming practice. Just to change one line of code, I would have to replicate the same code ten different times which will add nearly 500 lines of code.
So, my question is: Is there a way to dynamically change my method call based on the category type string argument.
I was thinking one possible way is to pass the method call in a string and convert it to a method call itself. For example, let's assume CategoryType string argument is "calculateCategoryOne()". So, data.get(i)."calculateCategoryOne()" would be recognized by the compiler as the method call itself. Is there a way to actually implement this?
I'm open to other ideas as well to reduce redundancy.
I would think using a functional interface would be appropriate here. You want different functionality depending on the categoryType, so passing in the function you want to use, rather than a String representation of it, would accomplish this.
#FunctionalInterface
public interface Calculate {
int calculate(Person data);
}
public static void calculate(List<Person> data, Calculate calculate) {
for(int i = 0; i < categoryData.size(); i++) {
if(calculate.calculate(data.get(i)) == firstPlace) {
...
}
}
}
and the call to the method would define what the calculation would be
calculate(list, p -> {
// calculation done here
});
or if this would happen frequently, you could predefine your categories once and pass those in:
Calculate categoryOne = p -> { ... };
Calculate categoryTwo = p -> { ... };
.
.
calculate(list, categoryOne);
I have a ussd application where I generate an interface and with predefined options e.g 1. my account 2. transactions 3. bill enquiry. the user keys in either 1 or 2 or 3 or any other predefined option on their handset. now since the input from all interfaces is the same values, to keep track of the user's progress i have states i set each time a user navigates to a certain interface. now my problem is the states are becoming too many I have about 30 states and the if else statement is starting to look like one big ball of spaghetti plus not forgetting this approach is not scalable. any one can help me do a better design probably one that's scalable.
if (state == 35) {//exit application
a = mm.exit(uid);
out.println(a);
} else if (state == 3) {
a = view.main_menu_nav(uid, value.trim());
out.println(a);
} else if (state == 4) {
a = view.my_account(uid);
out.println(a);
} else if (state == 5) {
a = view.my_account_nav(uid, value.trim());
out.println(a);
} else if (state == 6) {
String value = USSD_STRING;
a = view.transaction_nav(uid, value.trim());
out.println(a);
} else if (state == 7) {
a = view.deactivate_nav(uid, value.trim());
out.println(a);
}
In your example snippet, there's repetition of out.println(a) in each clause of the if, you can simplify the code by moving out.println(a) outside of the if. You could also use a switch instead of an if.
Neither of these ideas fundamentally improve the design, however.
I would suggest you look at the "State" design pattern. Essentially, you have a separate object for each state that knows how to handle interactions in that state, and an outer container that receives events, holds a reference the current state object, and delegates the events to it.
A second (orthogonal) suggestion is to name your methods to reveal intentions—i.e. behavior. The method deactivate_nav() is OK, but my_account(uid) does not say what the method does.
It's hard to give specific advice without more information on your specific problem.
You can use a Map and let the key be the state, the value is an object of an interface, e.g. StateAction which provides a proper method which you then call:
StateAction action = stateActions.get(state);
action.execute();
The interface would be defined as
interface StateAction
{
void execute();
}
The map can be filled programmatic:
stateActions.put(35, new StateAction
{
public void execute()
{
//exit application
YourType a = mm.exit(uid);
out.println(a);
}
});
stateActions.put(3, new StateAction
{
public void execute()
{
YourType a = view.main_menu_nav(uid, value.trim());
out.println(a);
}
});
// and so on ...
It's also possible to create a class for your action and let it implement the interface:
class AccountHandler implements StateAction
{
// ...
public void execute()
{
YourType a = view.my_account(uid);
out.println(a);
}
// ...
}
Add this with
stateActions.put(4, new AccountHandler());
I have two questions about Java Convention. I try to make use od Robert C. Martin's "Clean Code".
Following case:
public void startProgressIfAllowed() {
try {
tryStartProgressIfAllowed();
} catch (Exception exception) {
// log error
}
}
private void tryStartProgressIfAllowed() {
if (isStartProgressAllowed()) {
stopProgressOnCurrentlyStartedTask();
startProgressOnThisTask();
}
}
private boolean isStartProgressAllowed() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
private void stopProgressOnCurrentlyStartedTask() {
// Saves currently started task depending on checkbox selecion property and stops currently started.
// What is the correct way to get checkbox selecion property?
}
Proposed solution:
public void tryStartProgressIfAllowed() {
if (tryToStopProgressOnStartedTaskIfNecessary()) {
startProgressOnThisTask();
}
}
private boolean tryToStopProgressOnStartedTaskIfNecessary() {
// Calls JOptionPane.showConfirmDialog with JOptionPane.YES_NO_OPTION.
// Created dialog contains checkbox indicating that saving currently started task is required.
// Depending on checkbox selecion property saves task.
// returns boolean depending on JOptionPane.YES_NO_OPTION clicked button
}
But this approach doesn't meet the "Command Query Separation" principle, because tryToStopProgressOnStartedTaskIfNecessary(...) method performs some logic and returns success/failure value.
I think this approach also doesn't meet the "One level of abstraction per function" principle, because I suppose "check" and "save" operations are on different levels of abstraction.
Is the method name correct to avoid disinformation? Maybe better name would be tryToStopProgressAndSaveStartedTaskIfNecessary(...)?
Is there any better solution for above problem?
What about the following:
public void tryStartProgressOnThisTaskIfAllowed() {
tryStopTaskInProgressIfAllowed()
if (!isTaskInProgress()) {
tryStartProgressOnThisTask();
}
}
private void tryStopTaskInProgressIfAllowed() {
if (!isTaskInProgress()) {
return;
}
TaskInProgressResult result = whatToDoWithTaskInProgress();
if (result == Result.KEEP) {
return;
} else if (result == Result.DROP)
tryDropTaskInProgress();
} else if (result == Result.SAVE) {
trySaveTaskInProgress();
}
}
About your points:
You now have two separate methods for C and Q
I think the two things whatToDoWithTaskInProgress and tryDropTaskInProgress are the same level of abstraction. If you'd inline the code of one or the other you were absolutely right of course.
I changed some of the method names according to my taste :) The only thing I still don't like is the part "OnThisTask" because this task is somewhat meaningless. Maybe it's only because the rest of the code is unknown maybe OnNextTask or OnNewTask are better.
The problem we were having is that we were thinking in UI terms YES/NO + checkbox value. But it is much better to think in business terms here. I identified three different outcomes that are of interest: KEEP, SAVE, DROP How the answer is obtained should not matter to the calling method.
This seems something to ask on CodeReview, see the drop down at the top left of the page.
An example of how such stateliness is realized in Java SE: the regex Matcher class.
String s = ...
Pattern pattern = Pattern.compile("...");
Matcher m = pattern.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, ... m.group(1) ...);
}
m.appendTail(sb);
with m.matches() and m.lookingAt as alternative circuits too.
In short state is held in a processing class on the actual data (String here).
I'm writing a function where I'm essentially doing the same thing over and over. I have the function listed below
public String buildGarmentsString(List<Garment> garments)
{
StringBuilder garmentString = new StringBuilder(10000);
for(int i=0;i<4;i++)
{
garmentString.append(this.garmentProductId(i,garments.get(i).getProductId()));
garmentString.append(this.garmentColor(i,garments.get(i).getColor()));
for(int j=0;j<garments.get(i).getSizes().size();j++)
{
//check xxsml
if(garments.get(i).getSizes().get(j).getXxsml() >0)
{
garmentString.append(this.garmentSizes(i, Size.xxsml(),garments.get(i).getSizes().get(j).getXxsml()));
}
//check xsml
if(garments.get(i).getSizes().get(j).getXsml() > 0)
{
garmentString.append(this.garmentSizes(i,Size.xsml(),garments.get(i).getSizes().get(j).getXsml()));
}
//check sml
if(garments.get(i).getSizes().get(j).getSml() > 0)
{
garmentString.append(this.garmentSizes(i,Size.sml(),garments.get(i).getSizes().get(j).getSml()));
}
//check med
if(garments.get(i).getSizes().get(j).getMed() > 0)
{
garmentString.append(this.garmentSizes(i,Size.med(),garments.get(i).getSizes().get(j).getMed()));
}
//check lrg
if(garments.get(i).getSizes().get(j).getLrg() > 0)
{
garmentString.append(this.garmentSizes(i,Size.lrg(),garments.get(i).getSizes().get(j).getLrg()));
}
//check xlrg
if(garments.get(i).getSizes().get(j).getXlg() > 0)
{
garmentString.append(this.garmentSizes(i,Size.xlg(),garments.get(i).getSizes().get(j).getXlg()));
}
//check xxlrg
if(garments.get(i).getSizes().get(j).getXxl() >0)
{
garmentString.append(this.garmentSizes(i,Size.xxlg(),garments.get(i).getSizes().get(j).getXxl()));
}
//check xxxlrg
if(garments.get(i).getSizes().get(j).getXxxl() >0)
{
garmentString.append(this.garmentSizes(i,Size.xxxlg(),garments.get(i).getSizes().get(j).getXxxl()));
}
}
}
}
This is my garmentSizes function:
public String garmentSizes(int garmentNumber, String size,int numberToSend)
{
String garmentSizes = "&garment["+garmentNumber+"][sizes]["+size+"]="+numberToSend;
return garmentSizes;
}
I'm trying to figure out how I can get this done with a lot less code. I've read that with functional programming you can do things like pass in functions to parameters to other functions. After doing some reading online, I think I want to do something like this but I'm not sure how or what the best approach would be.
I have done some reading here on stack overflow and I've seen people mention using either the Command pattern or FunctionalJava or LambdaJ for trying to approximate this feature in Java. I've read over the documentation for the two libraries and read the Wikipedia Article on the Command Pattern, but I'm still not sure how I would use any of those to solve my particular problem. Can somebody explain this to me? As somebody that has never done any functional programming this is a bit confusing.
You could use local variables to decrease the amount of repetition. Say bySize = garments.get(i).getSizes().get(j) for example.
instead of size.getXxsml(), size.getXsml() etc. you could use an enum for sizes and loop on sizes.
The whole thing would then look like:
for(int j=0;j<garments.get(i).getSizes().size();j++) {
bySize = garments.get(i).getSizes().get(j);
for (Size s : Size.values()) {
if (bySize.get(s) > 0) {
garmentString.append(garmentSizes(i, s, bySize.get(s)));
}
}
}
The bySize.get(s) method could be implemented either with a switch that directs to the right method or directly in the enum and you could get rid of the getXsml etc. methods.
The only thing which differs between all your checks is this:
getXxsml/xxsml, getXsml/xsml, getSml/sml, etc.
If you could pass these values (as strings) to some upper-level method, and if
that upper-level method could eval i.e. execute these strings, then you can just
have an array of these values and pass that array to that upper-level method.
In Java, you can do something similar with reflection.
All these checks could indeed be simplified to much less
code through the use of reflection.
Look at:
java.lang.Class
java.lang.reflect.Method
java.lang.reflect.Field
java.lang.reflect.Constructor
and you will see what I mean.
From your code it appears that some Class has the following methods:
xxsml(), xsml(), sml(), med(), ..., xxxlg()
to get the amounts (?) available for each size.
You can design your data better, like this:
Have a "Size" type, that enumerates all sizes (could be Enum or some class with attribute String key)
Have a method that returns a List of all known sizes.
replace the above methods with amountFor(Size) This could be backed by a Map<Size, Integer>
For backward compatibility, you could rewrite the old methods along the lines:
int xxsml() {
return amountFor(Size.XXSML); // assuming you have a singleton instance
// for each well known size
}
Of course, in getGarmentString, you would then loop through the List of all known sizes:
for (Size sz : Size.getAllKnownSizes()) {
if (garments.get(i).getSizes().get(j).amountFor(sz) > 0) {
... do whatever must be done here
}
}
I have a question regarding structuring of code.
I have let us say three types of packages A,B and C.
Now, classes in package A contains classes which contain the main() function. These classes
need some command line arguments to run.
In package B, there are classes which contains some public variables, which need to be configured, at different times. For example before calling function A, the variable should be set or reset, the output differs according to this variable.
In package C, uses the classes in package B to perform some tasks. They do configure their variables as said before. Not only when the object is created, but also at intermediate stage.
Package A also has classes which in turn use classes from package B and package C. In order to configure the variables in classes of B and C, class in package A containing the main() function, reads command line arguments and passes the correct values to respective class.
Now, given this scenario, I want to use Apache Commons CLI parser.
I am unable to understand how exactly I should write my code to be structured in an elegant way. What is a good design practice for such scenario.
Initially I wrote a class without Apache to parse the command line arguments.
Since I want a suggestion on design issue, I will give an excerpt of code rather than complete code.
public class ProcessArgs
{
private String optionA= "default";
private String optionB= "default";
private String optionC= "default";
public void printHelp ()
{
System.out.println ("FLAG : DESCRIPTION : DEFAULT VALUE");
System.out.println ("-A <Option A> : Enable Option A : " + optionA);
System.out.println ("-B <Option B> : Enable Option B : " + optionB);
System.out.println ("-C <Option C> : Enable Option C : " + optionC);
}
public void printConfig()
{
System.out.println ("Option A " + optionA);
System.out.println ("Option B " + optionB);
System.out.println ("Option C " + optionC);
}
public void parseArgs (String[] args)
{
for (int i=0;i<args.length;i++)
{
if (args[i].equalsIgnoreCase ("-A"))
optionA = args[++i];
else if (args[i].equalsIgnoreCase ("-B"))
optionB = args[++i];
else if (args[i].equalsIgnoreCase ("-C"))
optionC = args[++i];
else
throw new RuntimeException ("Wrong Argument : " + args[i] + " :: -h for Help.");
}
}
}
Points to note -
I already have 50+ command line options and they are all in one place.
Every class uses only a group of command line options.
I tried to write an interface, somehow but I am unsuccessful. I am not sure if this is a good way to do it or not. I need some design guidelines.
Here is the code which I wrote -
public interface ClassOptions
{
Options getClassOptions();
void setClassOptions(Options options);
}
public class Aclass implements ClassOptions
{
private String optionA="defaultA";
private String optionB="defaultB";
public Options getClassOptions()
{
Options options = new Options();
options.addOption("A", true, "Enable Option A");
options.addOption("B", true, "Enable Option B");
return options;
}
public void setClassOptions(Options options, String args[])
{
CommandLineParser parser = new BasicParser();
CommandLine cmd=null;
try
{
cmd = parser.parse( options, args);
} catch (ParseException e)
{
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("ignored option");
}
if(cmd.hasOption("A"))
optionA = "enabled";
if(cmd.hasOption("B"))
optionB = "enabled";
}
}
I think the problems in such writing of code are -
There are different types of arguments like int, double, string, boolean. How to handle them all.
getClassOption() and setClassOption() both contain the arguments "A", "B" for example. This code is prone to errors made while writing code, which I would like to eliminate.
I think the code is getting repetitive here, which could be encapsulated somehow in another class.
Not all the arguments are required, but can be ignored.
Thank You !
I would recommend to you JCommander.
I think it's a really good Argument Parser for Java.
You define all the Argument stuff within annotations and just call JCommander to parse it.
On top of that it also (based on your annotations) can print out the corresponding help page.
You don't have to take care about anything.
I believe you will love it! :)
Take a look at it: http://jcommander.org/
There are a lot of examples and such!
Good Luck! :)
simple example for command line argument
class CMDLineArgument
{
public static void main(String args[])
{
int length=args.length();
String array[]=new String[length];
for(int i=0;i<length;i++)
{
array[i]=args[i];
}
for(int i=0;i<length;i++)
{
System.out.println(array[i]);
}