While starting to build an application, I stared using a switch case block with only five cases to be considered. Later when the build progressed, more cases came into picture and that started creating problems. I know I might have designed it wrongly at the first place, but if such things come as a change how do I effectively approach this? An example is given below
Starting with this
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
Later, a 100 cases come in
switch case 1: /*do function1()*/ break;
case 2: /*do function2()*/ break;
....
case 100: /*do function100()*/ break;
I am sure that converting these cases into 100 if conditions is not going to be a very good approach, so is there a way this can be done?
Please consider that the functions given in the code above are simple mathematical functions for now.
Consider an interface like this:
public interface MyFunction {
public void compute();
}
and a Map with the previous interface as values:
Map<Integer,MyFunction> myFunctionsMap = new HashMap<>();
You need to initialize the map with all of you functions:
myFunctionsMap.put(1,new MyFuntion() {
#Override
public void compute() {
/*do function1()*/
}
});
for each of your functions, the syntax might be a bit heavy with anonymous classes, you can implement you functions in separate classes and use them as well.
Now instead of the switch, you simply use the map:
myFunctionsMap.get(theValueSwitched).execute();
Depending of how you initialize the map, the values of the keys and how you use it, you might want to check myFunctionsMap.contains(theValueSwitched) (this would be your default case if you have one).
Edit: Java 8 shorter syntax would be myFunctionsMap.put(1,() -> {/*do function1()*/});
You could name your methods something like method1, method2, method3 , etc .. and use reflexion to call them, using you variable. You wouldn't have a lengthy switch, that way.
I have no ideas if that is efficient or not, though.
Here's a neat exemple, from wikipedia's reflection page.
Object foo = Class.forName("complete.classpath.and.Foo").newInstance();
// Alternatively: Object foo = Foo.class.newInstance();
Method m = foo.getClass().getDeclaredMethod("hello", new Class<?>[0]);
m.invoke(foo);
hope that helps
Related
I am trying to clean up a static function. Let me provide a template of this function here. It is a static function and is used only in two places in the code base one where the isClient is true and another where isClient is false.
public static void validate(BLangFunction resource, DiagnosticLog dlog, boolean resourceReturnsErrorOrNil,
boolean isClient) {
if (!resourceReturnsErrorOrNil) {
dlog.logDiagnostic(Diagnostic.Kind.ERROR, resource.pos, "Invalid return type: expected error?");
}
switch (resource.getName().getValue()) {
case WebSocketConstants.RESOURCE_NAME_ON_OPEN:
case WebSocketConstants.RESOURCE_NAME_ON_IDLE_TIMEOUT:
validateOnOpenResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_TEXT:
validateOnTextResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_BINARY:
validateOnBinaryResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_PING:
case WebSocketConstants.RESOURCE_NAME_ON_PONG:
validateOnPingPongResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_CLOSE:
validateOnCloseResource(resource, dlog, isClient);
break;
case WebSocketConstants.RESOURCE_NAME_ON_ERROR:
validateOnErrorResource(resource, dlog, isClient);
break;
default:
dlog.logDiagnostic(Diagnostic.Kind.ERROR, resource.pos,
"Invalid resource name " + resource.getName().getValue() + " in service ");
}
}
The problem with this code is that the dlog variable is passed to all the other called functions as well as the isClient variable. And the resourceReturnsErrorOrNil is used in only one place.
I thought of refactoring the code to have non-static functions so that dlog can be a class variable and there could be two classes one for client and other for service with all the common code in a super class. Then I thought that this function is used only in two places and should we have instance classes for these?
The source code of this function can be found here.
What would be the best way to refactor based on the clean code principles?
Then I thought that this function is used only in two places and should we have instance classes for these?
That really depends on your goal. I agree, the current code is far from ideal. And the things you outlined all make sense. So, to answer your question: yes, if you think it will be helpful to the quality of your code base, having an "instance" class that only gets used in two places is perfectly fine.
The other thing to carefully look at: maybe there is a way to get rid of that switch. You could for example use a map (key: your constants, value: some Functional interface ... that makes the corresponding validation).
The method should be made non static. This way, you can utilize dependency injection for the logging feature.
I'm trying to create Unit tests for a project. In my project I have a Menu Class, and a VerticalOptions Class.
My menu class has a private VerticalOptions object and a public handleInput method.
When I call my menu's handleInput(key) method, depending on the key I give it it'll do different things, namely call different methods of my VerticalOptions object.
I want to make a unitTest to see if the methods being called are the correct ones, how can I do that?
I've tried adding a Mockito spy to my menu, however since I want to test if the method being called was the method in the private VerticalOptions object, it doesn't really work.
I've also tried putting the spy on the VerticalOptions object, after getting it with a getVerticalOptions method, but it also doesn't work.
public void handleInput(InputKey key)
{
switch (key) {
case S:
case DOWN:
optionsInterface.cycleDown();
break;
case W:
case UP:
optionsInterface.cycleUp();
break;
case SPACE:
case ENTER:
optionsInterface.select();
break;
default:
break;
}
}
#Test
public void testInput() {
MainMenu menu = new MainMenu(game);
VerticalButtonInterface buttonInterface = menu.getOptionsInterface();
VerticalButtonInterface spy = spy(buttonInterface);
menu.handleInput(InputKey.DOWN);
verify(spy, times(1)).cycleDown();
}
This is the test failure I got:
Wanted but not invoked:
verticalButtonInterface.cycleDown();
-> at MenuTest.testInput(MenuTest.java:60)
Actually, there were zero interactions with this mock.
I will give you an alternative view on this. I have seen a lot of people going down the wrong path and when you do that, everything else becomes hard to do / test, which is exactly what you are doing now.
Start here, what are you trying to achieve?
I want to test and make sure that a certain method is called ...
Is this a good thing? What is a unit test not meant to have? That is deep knowledge of the code.
Why? Because every time you make slight changes to the code, you'll have to change the test because of this deep knowledge. if you have 1000 tests, you're in for a hard road.
Ok, so we now know what the problem is, so how do we solve it? Well, first let's make sure we can have a test without deep knowledge of the code.
How do we do that? Well, imagine that your code adds an extra step, a flag which sets a state. You might have a flag which stores a resulting state ...
you have 3 methods you want to call, so you will need 3 different states, so create a variable which reflects that, be it a string, or an enum or whatever else makes you happy.
For example sake, let's say we create a string with 3 possible values: cycleDown, cycleUp and select.
your code starts to look something like :
public string handleInput(InputKey key)
{
String state = determineState(key);
SomeType someResult = executeActionForState(state);
}
public String determineState(string key)
{
String state = "";
switch (key) {
case S:
case DOWN:
state = "cycleDown";
break;
case W:
case UP:
state = "cycleUp";
break;
case SPACE:
case ENTER:
state = "select";
break;
default:
break;
}
return state;
}
public void executeActionForState(string state)
{
if ( state == "cycleup" ) {
}
etc etc
}
Now, I may not necessarily code your example like this, this is a bit forced, it depends on what other things you're doing with the code, but this is meant to show how you separate functionality from UI aspects.
I can easily test the state method, I can change its code and I wouldn't have to change the test, because the test would look at the inputs and outputs and not how things are achieved.
Unit testing is about functionality, it's about having simple tests that don't need to change once created. Verifying that a method has been called doesn't give you anything worthwhile, because you don't know what that method does later.
UI stuff you can test in other ways, unit testing is only about correct functionality. If you do not make this separation clear then you will have trouble maintaining your tests, it will become harder and harder until you give up.
You would test that you get the correct state, then you test that cycleUp method does something correct based on your requirements and that's how you know each part works in isolation. Later on you start looking at integration tests, Automated UI tests, but those are different things. Keep unit testing for what it's meant to do, keep it simple, keep it not tied to other code and then everything becomes simple. You won't need to mock much, you won't need to worry too much about complex setups and you won't need to change your tests every time something in the code changes.
Now, to address the final part of the question, private methods, you test them by observing their outputs. You must have something public in your class that changes when a private method is called. So test that.
I have two switch statements that are identical in structure but the cases do different things. How do I possibly combine them? Or are there any better design suggestions instead of using two switch statements?
This is how the first switch statement looks:
switch(var){
case 1:
functionA();
break;
case 2:
functionB();
break;
}
The second looks like this:
switch(var){
case 1:
functionC();
break;
case 2:
functionD();
break;
}
Problem is, functionA() cannot be called at the same time with functionC() and same goes for functionB() and functionD() - they are to be called at different times.
Forgive me if this sounds silly, but is there a way to re-use one switch statement for different situations?
NB: This is not a "how do I do this?" question, but a "how do I do this BETTER question".
In my optionion there is no need to further simplify your switch statements, since they are readable and do different things. Also, in order to simplify you would need to add an additional layer of abstraction, which is not (really) possible here.
The only thing you could abstract here is the var parameter. Altough i would not recommend it, maybe you can try something like this:
private Consumer<Integer> createConsumer(Runnable... actions) {
return i -> {
if (actions.length < i)
throw new IllegalArgumentException();
actions[i].run();
};
}
You can create a consumer, which accepts an arbitary amount of Runnable objects
var consumer = createConsumer(
() -> System.out.println("First"),
() -> System.out.println("Second"),
() -> System.out.println("Third"));
and execute it like
consumer.accept(0);
If you also need a default statement Consumer<Integer> createConsumer(Runnable... actions, Runnable defaultOption) could come to rescue, then the IllegalArgumentException would also be superfluous.
However, this would just be some functional style of switch statement, which could make things even more complicated, whenever the parameter does not start at 0, but some other number (you would need to subtract till 0) or if you switch block has "gaps" bewteen numbers (0, 1, 3, ...).
For example:
3 methods exist
"map1method,
map2method,
map3mehtod"
and I want to call the right one depending on what the integer 'activemap' has currently stored in it.
I could do an If statement
"If (activemap == 1)
map1method;
elseif (activemap ==2)
..."
But is there a possible way of using the integer more efficiently?
Like a "map(activemap)method"
Also could I also call a specific array in a batch of them in the same fashion.
This is all in java by the way.
It is possible via reflection but I would urge you to stay away from that approach. Why not have all three methods built into one? One option would be to use a switch statement to handle the various cases:
void mapMethod(int activemap) {
switch (activemap) {
case 1:
// map1method
break;
case 2:
// map2method
break;
case 3:
// map3method
break;
default:
break;
}
}
Now, you can call
mapMethod(activemap)
If you want to take the reflection approach instead (which as I said I don't think you should), you can do something along the lines of
String methodName = "map" + activemap + "method";
MyClass.class.getDeclaredMethod(methodName).invoke(null);
A switch statement would be slightly easier to read:
switch(activemap) {
case 1: map1method(); break;
case 2: map2method(); break;
}
You could use reflection to build the method name up at runtime, but that wouldn't be simpler. Reflection is a lot of code.
The most effective way to do this is to either create an enum to represent the different calls and use the int as a lookup for the enum value, or if that's not possible, to use a switch statement. You can use reflection to accomplish what you're talking about (look up a method at runtime based on its name), but it's less efficient and more cumbersome than either of those options.
You can do it using Reflection, It will be something like this:
java.lang.reflect.Method method;
method = myObject.getClass().getMethod("map+"activemap"+method", param1.class, param2.class, ..);
method.invoke(object, arg1, arg2,...);
The following code does not compile because eater is defined twice:
switch (vegetable) {
case TOMATO:
Eater eater = new Eater(Tomato.class, many parameters);
eater.eat(more parameters);
return true;
case POTATO:
Eater eater = new Eater(Potato.class, many parameters);
eater.eat(more parameters);
return true;
case CARROT:
doSomethingElse();
return true;
}
Should I:
Use separate variables `tomatoEater` and `potatoEater`, making the code less maintainable?
Define `eater` before the `switch`, making it accessible to more than it should?
Define `eater` the first time only, leading to potential confusion?
Add braces, making the code more verbose?
Any better idea?
I would personally either use braces, or just abandon the local variable completely:
new Eater(Potato.class, many parameters)
.eat(more parameters);
The disadvantage of this is that it makes it a little harder to debug. Obviously this isn't your real code though... which makes it hard to say the right thing to do. It's quite possible that the right thing to do is actually to break out the bodies of the cases into separate methods.
Why not this:
switch (vegetable)
{
case TOMATO:
new Eater(Tomato.class, many parameters).eat(more parameters);
return true;
case POTATO:
new Eater(Potato.class, many parameters).eat(more parameters);
return true;
case CARROT:
doSomethingElse();
return true;
}
If you dont have any use of the Eater reference anywhere else later, I would do this.
Not quite the same logic as your method (carrot is treated as default) but shows an alternative approach (with some more behind the scenes wiring that I haven't worried about here):
Eater eater = vegetable.getEater(many parameters);
if (eater != null) eater.eat(more parameters);
else doSomethingElse();
return true;
How would using separate variables make the code less maintainable? (first bullet point). If anything I would say it would do the opposite as the variable name better explains what it is. I would go with that if keeping it in that scope is important to you.
Maybe using a switch isn't such a good idea at all.
In what better example can represent a switch statement in Java ?