The Application
I am writing an application that executes certain functions depending on user input.
E.g. if the user input were to be
"1 2 add" the output would be "3".
I aim to implement many such methods (div, modulo, etc.). As my Scanner recognizes a function name like "add" the function "add()" should be called.
My Way
My way to do this is to let a FunctionHandler class evaluate the input.
Main:
String inputCommand = sc.nextCommand();
functionHandler.handle(inputCommand);
Function Handler:
public class FunctionHandler {
public void handle (String functionName) {
if (functionName.equals("add")) {
add();
} else if (functionName.equals("div") {
div();
}
}
private void add() {
.......
}
....
}
The Problem with that
As I am adding more and more functions the if statement gets very large, and of course the FunctionHandler class too. Also, whenever I add a new function, I have to change code in two places: I have to define the function, and then add the else if clause in handle() to call the function. Which means two pieces of information that should be encapsulated are "stored" completely independent from each other.
I was wondering what the best practice was to solve this kind of situation?
My Ideas
I was thinking about using enums, but they don't seem to fit well in this case.
Another idea I had was creating an interface Function, and then a class for each function that implements Function. The interface would have two methods:
getName()
execute()
Then I could create an array (manually) of Functions in the FunctionHandler, through which I could loop to see if the command the user enters matches getName().
However, having a different class for each function is not very clean either, and it also does not get rid of the problem that for each function I am adding I have to do it in two places: the class and the array.
This question is only about finding out how to solve this problem cleanly. A pointer in the right direction would be appreciated!
Thanks a lot!
Another option would be to keep a Map of handlers. If you're using Java 8, they can even be method references.
// InputType and ResultType are types you define
Map<String, Function<InputType, ResultType>> operations = new HashMap<>();
operations.put("add", MathClass::add);
// ...
ResultType result = operations.get(userInput).apply(inputObject);
One downside to doing it this way is that your input and output types must be the same for all operations.
You could create a custom annotation for the various functions. Then you could employ your array idea, but have it use reflection to discover which functions have your new annotation and what their names are.
As background, take a look at http://www.oracle.com/technetwork/articles/hunter-meta-2-098036.html and http://www.oracle.com/technetwork/articles/hunter-meta-3-092019.html. They're a bit old, but seem to address the necessary ideas.
You can always use reflection if you want a short solution.
In your handle method you could do something like this:
Method m = this.getClass().getMethod(functionName, new Class[]{});
m.invoke(this, new Object[]{});
Assuming you do not have a lot of functions that you want to do this way, and do not want to expose yourself to the security risks caused by reflection, you could use a string switch, like this:
void handleFunction(String function) {
switch (function) {
case "foo":
foo();
break;
case "bar":
bar();
break;
default:
throw new IllegalArgumentException("Unknown function " + function);
break;
}
}
Starting Java 7, you can use Strings in a switch statement and the compiler will make something reasonable out of it
I would do something like this:
public class FunctionTest {
private static final Map<String, Runnable> FUNCTIONS = new HashMap<String, Runnable>() {{
put("add", () -> System.out.println("I'm adding something!"));
put("div", () -> System.out.println("I'm dividing something!"));
}};
public void handle(String functionName) {
if (!FUNCTIONS.containsKey(functionName)) {
throw new IllegalArgumentException("No function with this name: " + functionName);
}
FUNCTIONS.get(functionName).run();
}
}
You basically can use any functional interface in place of Runnable, I used it, because it matches your add() method. You can map the names of the functions to their actual executable instance, get them by name from the Map and execute them.
You could also create an enum with the desired executable blocks:
public class FunctionsAsEnumsTest {
private static enum MyFunction {
ADD {
#Override public void execute() {
System.out.println("I'm adding something");
}
},
DIV {
#Override public void execute() {
System.out.println("I'm dividing something");
}
};
public abstract void execute();
}
public void handle(String functionName) {
// #toUpperCase() might not be the best idea,
// you could name your enums as you would the methods.
MyFunction fn = MyFunction.valueOf(functionName.toUpperCase());
fn.execute();
}
}
Related
Is there anyway to avoid these if conditions? because there may be different type of objects coming in.
if ("OpenOrder".equals(order.getClass().getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
}
if ("ExecutionOrder".equals(order.getClass().getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
You can use a Router pattern to do this. Simple add the computations in a Map like this:
Map<String, Function> router = new HashMap<>();
router.put("OpenOrder", (value) -> OpenOrderBuilder.createOFSMessage((OpenOrder) value));
router.put("ExecutionOrder", (value) -> ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order));
And you can route the order using the String key. Here is a "OpenOrder" example:
String result = (String) router.get("OpenOrder").apply(order);
There are many ways to do it. Which one to choose, depends on your needs and in this case in particular on how many different types of objects you will have.
I suggest looking at concepts like interfaces and inheritance and on specific design patterns.
One approach I tend to like, although still not perfect, works as follows:
interface Order {
}
interface OrderBuilder<T> {
T forType();
Object createOFSMessage(Order order);
}
class OpenOrderBuilder<OpenOrder> implements OrderBuilder {
#Override
OpenOrder forType() {
return OpenOrder.class;
}
...
}
class ExecutionOrderBuilder<ExecutionOrder> implements OrderBuilder {
#Override
ExecutionOrder forType() {
return ExecutionOrder.class;
}
...
}
class MyProcessor {
Map<Class, OrderBuilder> obs;
public void initialize() {
List<OrderBuilder> builders = new ArrayList<>();
builders.add(new OpenOrderBuilder());
builders.add(new ExecutionOrderBuilder());
obs = new HashMap<Class, OrderBuilder>();
for(OrderBuilder b : builders) {
obs.put(b.forType(), b);
}
}
public Object createOFSMessage(Order order) {
return obs.get(order.getClass()).createOFSMessage(order);
}
}
In the above example, adding a new implementation would just consist of adding an entry to the builders collection. While in the example above it's done manually, normally this is done through Dependency Injection and frameworks like spring (in which case, the initialize method may turn into a constructor with builders as an #Autowired argument).
There are of course other ways, some more simple some more complicated. The best way really depends on what you have to do and one key rule: the less code you have the better.
First one should not forget the switch-on-string:
switch (order.getClass().getSimpleName()) {
case "OpenOrder":
return OpenOrderBuilder.createOFSMessage((OpenOrder) order); //Returns String
case "ExecutionOrder":
return ExecutionOrderBuilder.createOFSMessage((ExecutionOrder) order); //Returns String
}
The code however shows inheritance being used in combination with static child class factories. Evidently a createOFSMessage is not desired in the Order base class.
Then use a non-static "builder" - a factory. Follow the strategy pattern.
If you already know the type when calling the method, this code can help you :
private String CreateOFSMessage(Class<T> classOrder) {
if ("OpenOrder".equals(classOrder.getSimpleName())) {
return OpenOrderBuilder.createOFSMessage((classOrder) order);
}else if ("ExecutionOrder".equals(classOrder.getSimpleName())) {
return ExecutionOrderBuilder.createOFSMessage((classOrder) order);
}
}
To me, if-else if is too long and hard to read.
Is there some table-driven approach I can use to map an input value to call a specific method for that value?
For example:
for(String id:ids){
Test test = new Test();
if(id == "101") {
test.method1();
}else if(id=="102") {
test.method2();
}else if(id=="103"){
test.method3();
...
...
static Map<String,Method> methods = new HashMap<String,Method>();
...
static {
methods.put("101",Test.class.getMethod("method1",null));
methods.put("102",Test.class.getMethod("method2",null));
...
}
...
for( String id : ids ) {
Test test = new Test();
Method m = methods.get(id);
if (m != null) {
m.invoke(test,null);
}
}
Of course, all this really does is trade the pain of the if/else chain for the pain of initializing the hash with all the methods.
You can use reflection to call method. Construct the method name from the string and Use Method Class from java.lang.reflect namespace to invoke the method and pass parameters.
Something like this
Method theMethod = yourClass.getClass().getMethod("methodName", null);
method.invoke(yourClass, );
As it is, your code is not quite correct, as it's using == to check equality of strings.
You should use the equals method:
for(String id: ids){
Test test = new Test();
if(id.equals("101")) {
test.method1();
}else if(id.equals("102")) {
test.method2();
}else if(id.equals("102")){
test.method3();
// etc.
}
}
Other answers have suggested a creating a method map Map<String,Method> and using reflection. This will work and may be perfectly reasonable for your use, but loses some compile-time type safety checks.
You can get those checks back by defining an interface and populating a map with instances of that interface:
interface TestMethod {
void execute(Test test);
}
private static HashMap<String, TestMethod> methodMap = new HashMap<String, TestMethod>();
static {
methodMap.put("101", new TestMethod(){
#Override
public void execute(Test test) {
test.method1();
}
});
methodMap.put("102", new TestMethod(){
#Override
public void execute(Test test) {
test.method2();
}
});
methodMap.put("103", new TestMethod() {
#Override
public void execute(Test test) {
test.method3();
}
});
// etc.
}
and then your loop can be coded as
for (String id: ids) {
Test test = new Test();
methodMap.get(id).execute(test);
}
As it is here, this unfortunately makes the code longer and leaves it at least as difficult to read. But if you're using Java 8, you can use lambda expressions to populate the map, which would make the static initializer block look more like:
static {
methodMap.put("101", t -> t.method1();
methodMap.put("102", t -> t.method2();
methodMap.put("103", t -> t.method3();
// etc.
}
and then it might actually be worth doing.
However, if this sort of conditional based on some kind of string "code" is common in your application, and especially if you have multiple conditionals depending on the same codes, you might want a much broader redesign to encapsulate the different actions done for the different codes in a class hierarchy and use polymorphism instead of either if-else (or switch) or a method map lookup. You're still likely to need some conditionals to build the instances of your classes, but the code might be greatly improved.
I am building a HTTP server for my android device.
I am using a lot of IF-ELSE statements to handle differnt requests.
As I will be sharing my code with other people for later use, I will have to make it as legible as possible. Right now, I can't even read my code with ease.
I think the problem comes from using a lot of IF-ELSE statements in one class.
For example.
if(purpose.equals("readProfile"){
.....
}
else if(purpose.equals("writeProfile"){
.....
}
....
I tried classifying them in category and ordered the conditions according to their category. But not a lot of legebility was improved.
Then I tried writing short comments infront of each conditions. But this made even more mess.
What can be done to increase legibility for conditional statements?
As Luiggi Mendoza stated, this is a follow up of a previous question...
If you are using Java 7, you can use a switch-case statement for strings
//month is a String
switch (month.toLowerCase()) {
case "january":
monthNumber = 1;
break;
//partsleft out for sake of brevity ..
default:
monthNumber = 0;
break;
}
(excerpt from the Oracle Java Tutorials, referenced above.)
Refactoring
However, this huge if-else is just part of the problem. As this seems to be a structure growing over time, I'd recommend a thorough refactoring, and using what seems to me is a Strategy pattern. You should:
Formulate an interface which covers the boundaries for all the use cases:
interface MyStrategy {
void execute(MyInputContext input, MyOutputContext output);
}
(using a void method with MyInputContext and MyOutputContext are just one approach, this is just an example, but to handle requests that have responses, this makes sense, just like how Servlets work)
Refactor the content of the big IF-ELSE statement into instances of this interface (these will be the strategies):
//VERY simplified...
class ReadProfileStrategy implements MyStrategy {
void execute(MyInputContext input, MyOutputContext output) {
//do the stuff that was in the if-else block in the "readProfile" part
}
}
//... at the branching part:
MyInputContext input; //build this here
MyOutputContext output; //build this here
switch (purpose) {
case "readProfile":
// no need to always instantiate this, it should be stateless...
new ReadProfileStrategy().execute();
break;
//... left out for sake of brevity
}
Refactoring step 2
If this is done, you can add the string IDs to the interface, and the instances themselves, and get rid of the if-else or switch statement altogether, you could create a Map populated even through an IOC container (like), to be up to date, and completely flexible.
class ReadProfileStrategy implements MyStrategy {
String getID() {
return "readProfile";
}
void execute(MyInputContext input, MyOutputContext output) {
//do the stuff that was in the if-else block in the "readProfile" part
}
}
In the class when requests are processed
private final Map<String, MyStrategy> strategyMap; //fill the map using your favorite approach, like using Spring application context, using the getCode() to provide the key of the map
In the processing logic:
MyStrategy strategy = strategyMap.get(purpose);
if(strategy!=null) {
strategy.execute();
}
else {
//handle error here
}
This may be out of scope, but just an observation
try using
if("readProfile".equals(purpose){} instead of
if(purpose.equals("readProfile"){}.
It will help to avoid null pinter exception
Enums can help - you can also add functionality to them.
public void test(String purpose) {
if (purpose.equals("readProfile")) {
// Read.
} else if (purpose.equals("writeProfile")) {
// Write.
}
}
enum Purpose {
readProfile {
#Override
void doIt() {
// Read.
}
},
writeProfile {
#Override
void doIt() {
// Write.
}
};
abstract void doIt();
}
public void test2(String purpose) {
Purpose.valueOf(purpose).doIt();
}
You can try using some kind of Action-Interface with implementations for each block and preload a map with concrete Implementations of this action.
interface Action {
void execute();
}
Map<String, Action> actions = new HashMap<>();
actions.put("readProfile", new Action() { ... });
actions.put("writeProfile", new Action() { ... });
actionMap.get(purpose).execute();
That will lower your cyclomatic complexity as well. Of course you should preload the map only once.
Well, If it makes sense to separate code inside if-else condition to another class, perhaps use Factory pattern. Also make all separated classes implement common interface (eg: MyActivity.class) with a method such as execute().
Factory decides what object (ReadProfile.class, WriteProfile.class etc.) has to be created based on the string you pass and then call execute() method.
MyActivity obj = MyFactory.createMyActivity(String)
obj.execute(...);
This is the second time I found myself writing this kind of code, and decided that there must be a more readable way to accomplish this:
My code tries to figure something out, that's not exactly well defined, or there are many ways to accomplish it. I want my code to try out several ways to figure it out, until it succeeds, or it runs out of strategies. But I haven't found a way to make this neat and readable.
My particular case: I need to find a particular type of method from an interface. It can be annotated for explicitness, but it can also be the only suitable method around (per its arguments).
So, my code currently reads like so:
Method candidateMethod = getMethodByAnnotation(clazz);
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlyMethod(clazz);
}
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
}
if (candidateMethod == null) {
throw new NoSuitableMethodFoundException(clazz);
}
There must be a better way…
Edit: The methods return a method if found, null otherwise. I could switch that to try/catch logic, but that hardly makes it more readable.
Edit2: Unfortunately, I can accept only one answer :(
To me it is readable and understandable. I'd simply extract the ugly part of the code to a separate method (following some basic principles from "Robert C.Martin: Clean Code") and add some javadoc (and apologies, if necessary) like that:
//...
try {
Method method = MethodFinder.findMethodIn(clazz);
catch (NoSuitableMethodException oops) {
// handle exception
}
and later on in MethodFinder.java
/**
* Will find the most suitable method in the given class or throw an exception if
* no such method exists (...)
*/
public static Method findMethodIn(Class<?> clazz) throws NoSuitableMethodException {
// all your effort to get a method is hidden here,
// protected with unit tests and no need for anyone to read it
// in order to understand the 'main' part of the algorithm.
}
I think for a small set of methods what you're doing is fine.
For a larger set, I might be inclined to build a Chain of Responsibility, which captures the base concept of trying a sequence of things until one works.
I don't think that this is such a bad way of doing it. It is a bit verbose, but it clearly conveys what you are doing, and is easy to change.
Still, if you want to make it more concise, you can wrap the methods getMethod* into a class which implements an interface ("IMethodFinder") or similar:
public interface IMethodFinder{
public Method findMethod(...);
}
Then you can create instances of you class, put them into a collection and loop over it:
...
Method candidateMethod;
findLoop:
for (IMethodFinder mf: myMethodFinders){
candidateMethod = mf.findMethod(clazz);
if (candidateMethod!=null){
break findLoop;
}
}
if (candidateMethod!=null){
// method found
} else {
// not found :-(
}
While arguably somewhat more complicated, this will be easier to handle if you e.g. need to do more work between calling the findMethods* methods (such as more verification that the method is appropriate), or if the list of ways to find methods is configurable at runtime...
Still, your approach is probably OK as well.
I'm sorry to say, but the method you use seems to be the widely accepted one. I see a lot of code like that in the code base of large libraries like Spring, Maven etc.
However, an alternative would be to introduce a helper interface that can convert from a given input to a given output. Something like this:
public interface Converter<I, O> {
boolean canConvert(I input);
O convert(I input);
}
and a helper method
public static <I, O> O getDataFromConverters(
final I input,
final Converter<I, O>... converters
){
O result = null;
for(final Converter<I, O> converter : converters){
if(converter.canConvert(input)){
result = converter.convert(input);
break;
}
}
return result;
}
So then you could write reusable converters that implement your logic. Each of the converters would have to implement the canConvert(input) method to decide whether it's conversion routines will be used.
Actually: what your request reminds me of is the Try.these(a,b,c) method in Prototype (Javascript).
Usage example for your case:
Let's say you have some beans that have validation methods. There are several strategies to find these validation methods. First we'll check whether this annotation is present on the type:
// retention, target etc. stripped
public #interface ValidationMethod {
String value();
}
Then we'll check whether there's a method called "validate". To make things easier I assume, that all methods define a single parameter of type Object. You may choose a different pattern. Anyway, here's sample code:
// converter using the annotation
public static final class ValidationMethodAnnotationConverter implements
Converter<Class<?>, Method>{
#Override
public boolean canConvert(final Class<?> input){
return input.isAnnotationPresent(ValidationMethod.class);
}
#Override
public Method convert(final Class<?> input){
final String methodName =
input.getAnnotation(ValidationMethod.class).value();
try{
return input.getDeclaredMethod(methodName, Object.class);
} catch(final Exception e){
throw new IllegalStateException(e);
}
}
}
// converter using the method name convention
public static class MethodNameConventionConverter implements
Converter<Class<?>, Method>{
private static final String METHOD_NAME = "validate";
#Override
public boolean canConvert(final Class<?> input){
return findMethod(input) != null;
}
private Method findMethod(final Class<?> input){
try{
return input.getDeclaredMethod(METHOD_NAME, Object.class);
} catch(final SecurityException e){
throw new IllegalStateException(e);
} catch(final NoSuchMethodException e){
return null;
}
}
#Override
public Method convert(final Class<?> input){
return findMethod(input);
}
}
// find the validation method on a class using the two above converters
public static Method findValidationMethod(final Class<?> beanClass){
return getDataFromConverters(beanClass,
new ValidationMethodAnnotationConverter(),
new MethodNameConventionConverter()
);
}
// example bean class with validation method found by annotation
#ValidationMethod("doValidate")
public class BeanA{
public void doValidate(final Object input){
}
}
// example bean class with validation method found by convention
public class BeanB{
public void validate(final Object input){
}
}
You may use Decorator Design Pattern to accomplish different ways of finding out how to find something.
public interface FindMethod
{
public Method get(Class clazz);
}
public class FindMethodByAnnotation implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByAnnotation(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByAnnotation(Class clazz)
{
return getMethodByAnnotation(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByAnnotation(clazz) : r;
}
}
public class FindMethodByOnlyMethod implements FindMethod
{
private final FindMethod findMethod;
public FindMethodByOnlyMethod(FindMethod findMethod)
{
this.findMethod = findMethod;
}
private Method findByOnlyMethod(Class clazz)
{
return getMethodOnlyMethod(clazz);
}
public Method get(Class clazz)
{
Method r = null == findMethod ? null : findMethod.get(clazz);
return r == null ? findByOnlyMethod(clazz) : r;
}
}
Usage is quite simple
FindMethod finder = new FindMethodByOnlyMethod(new FindMethodByAnnotation(null));
finder.get(clazz);
... I could switch that to try/catch logic, but that hardly makes it more readable.
Changing the signature of the get... methods so you can use try / catch would be a really bad idea. Exceptions are expensive and should only be used for "exceptional" conditions. And as you say, the code would be less readable.
What is bothering you is the repeating pattern used for flow control--and it should bother you--but there isn't too much to be done about it in Java.
I get really annoyed at repeated code & patterns like this, so for me it would probably be worth it to extract the repeated copy & paste control code and put it in it's own method:
public Method findMethod(Class clazz)
int i=0;
Method candidateMethod = null;
while(candidateMethod == null) {
switch(i++) {
case 0:
candidateMethod = getMethodByAnnotation(clazz);
break;
case 1:
candidateMethod = getMethodByBeingOnlyMethod(clazz);
break;
case 2:
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
break;
default:
throw new NoSuitableMethodFoundException(clazz);
}
return clazz;
}
Which has the disadvantage of being unconventional and possibly more verbose, but the advantage of not having as much repeated code (less typos) and reads easier because of there being a little less clutter in the "Meat".
Besides, once the logic has been extracted into it's own class, verbose doesn't matter at all, it's clarity for reading/editing and for me this gives that (once you understand what the while loop is doing)
I do have this nasty desire to do this:
case 0: candidateMethod = getMethodByAnnotation(clazz); break;
case 1: candidateMethod = getMethodByBeingOnlyMethod(clazz); break;
case 2: candidateMethod = getMethodByBeingOnlySuitableMethod(clazz); break;
default: throw new NoSuitableMethodFoundException(clazz);
To highlight what's actually being done (in order), but in Java this is completely unacceptable--you'd actually find it common or preferred in some other languages.
PS. This would be downright elegant (damn I hate that word) in groovy:
actualMethod = getMethodByAnnotation(clazz) ?:
getMethodByBeingOnlyMethod(clazz) ?:
getMethodByBeingOnlySuitableMethod(clazz) ?:
throw new NoSuitableMethodFoundException(clazz) ;
The elvis operator rules. Note, the last line may not actually work, but it would be a trivial patch if it doesn't.
According to anti-if campaign it is a best practice not to use ifs in our code. Can anyone tell me if it possible to get rid of the if in this piece of code ? (switch is also not an option, The point is to remove the conditional logic, not replace ifs with similar language constructs)
if(s == "foo")
{
Writeln("some logic here");
}
else if(s == "bar")
{
Writeln("something else here");
}
else if(s == "raboof")
{
Writeln("of course I need more than just Writeln");
}
(language: Java or C#)
Here's one way... :)
delegate void DoStuff();
...
IDictionary<string, DoStuff> dict = new Dictionary<string, DoStuff>();
dict["foo"] = delegate { Console.WriteLine("some logic here"); };
dict["bar"] = delegate { Console.WriteLine("something else here"); };
dict["raboof"] = delegate { Console.WriteLine("of course I need more than just Writeln"); };
dict["foo"]();
Make use of the strategy pattern.
In Java terms:
public interface Strategy {
void execute();
}
public class SomeStrategy implements Strategy {
public void execute() {
System.out.println("Some logic.");
}
}
which you use as follows:
Map<String, Strategy> strategies = new HashMap<String, Strategy>();
strategies.put("strategyName1", new SomeStrategy1());
strategies.put("strategyName2", new SomeStrategy2());
strategies.put("strategyName3", new SomeStrategy3());
// ...
strategies.get(s).execute();
Make an associative data structure. Map<String, String> in Java, IDictionary<string, string> in C#. Initialize it at the beginning of time, and then ...
Looking at the campaign, it's very poorly explained. There's nothing wrong with ifs, but in certain cases they can indicate that you're not using OOP to its full potential.
What the campaign is trying to promote is increased use of polymorphism in order to decouple calling code from the type of object it is looking at.
You would use some smarter object instead of s being a string:
interface I {
public String getName();
public void doSomething();
}
class A implements I {
public String getName() { return "one"; }
public void doSomething() { ...; }
}
class B implements I {
public String getName() { return "two"; }
public void doSomething() { ...; }
}
Then you can replace the ifs with:
I obj = ...get an A or B from somewhere...;
obj.doSomething();
write classes with virtual methods which is derived from your abstract base class SomeThingWriter.
then every class which are derived from base class should implement a function like writeSomething or whatever you want.
abstract class MyBaseClass
{
public abstract void writeSomething();
}
class DerivedClass1 : MyBaseClass
{
public override void writeSomething()
{
Writeln("something else here 1");
}
}
class DerivedClass2 : MyBaseClass
{
public override void writeSomething()
{
Writeln("something else here 2");
}
}
than just call like
MyBaseClass c = new DeriveClass1();
c.writeSomething();
c = new DerivedClass2();
c.writeSomething();
In some cases it might be legit to avoid the if structure
in others its just plain idiocy to try to avoid if.
While the examples provided to avoid the if structure are valid alternatives you should ask yourself this:
Why am i making my code unnecessarly complicated to avoid a simple if structure ?
If the only reason is that you have to because of the anti-if campaign then its bad reason
Java
Use an enum which implements a certain method.
enum MyEnum{
foo{
public void mymethod(String param1, String param2){
//dostuff...
}
},
bar{
public void mymethod(String param1, String param2){
//dostuff...
}
};
public abstract void mymethod(String param1, String param2);
}
Then in your class :
MyEnum.valueOf(mystring).mymethod(param1, param2);
First of all, be very attentive when reading such "anti" campaigns.
Ask yourself if Anti IF campaign would like eliminate the logic in the applications?!
The ideas could have a good application in one situation and a stupid in another one. Be reasonable.
It may be possible that multiple usage of IF may encumber the reader of the code. but this is any reason to eliminate the if from your code, more that than, this is almost impossible.
By the way anywhere in the MS design guidelines is indicated do not use if (like is done, by e.g. for the goto statement usage of which is not recommended)...
C#
switch (myStringVar)
{
case "one": doSomething(); break;
case "two": doSomething(); break;
case "three": doSomething(); break;
default: doSomething(); break;
}
Finally, it reduces this code to the if s... so, only for readability is better, not for performance.
Actually, if Microsoft believes that switch (in c#) is better to replace with if's - OK, I will use (in the concrete situation that you described) the switch.
By the way, it seems that the campaign responds to your question very clear in this example
i'd like to point out that so far, every answer to this question with a code example has a solution that is far more complicated than the original code, and likely much slower.
this is a classic case of an optimization being performed in entirely the wrong context. in some cases, code will become clearer through using OO properly, such as eliminating long chains of type checks. however, simply removing all if statements for the sake of removing them only serves to obfuscate your code.
the if statements (conditional jumps) are still going to happen, be it in your code or the interpreter. keeping them lexically close has many readability and maintenance advantages that are lost through excessive OO use. there is a balance that must be struck between local vs distant logic, but it should never spill over into obfuscation.
for the question at hand, the clearest construct that will avoid the if is probably a hash table / associative array containing anonymous functions, which, for a small number of keys, is effectively just a slow switch statement.
The example you have given I would not change (though I guess you realise it wouldn't need changing)- I'm guessing you are using it as a representational example.
In Fowler's Refactoring book, he discusses the Replace Conditional with Polymorphism. That's what I see as a good use to replace if/switch statements (where appropriate).
I don't think you are making a fair comparison here.
From the look of it the Anti-if campaign is just about practicing a better design approach.
However in your case you can see from all the above examples that if can not be removed from the surface and will always exist somewhere down in the center.
And why exactly is that?
Well If is a general purpose of life. I don't mean to say start coding if every where but in general without if there is no differentiation, if brings decisions and purpose, if that wasn't there then every object in the world would just execute as its suppose to without even knowing anything other then it self. And very simple you wouldn't have asked this question. :)
I think you are looking for Factory Patterns.
You can conceivably do something similar to the "strategy" pattern above using a map of Method calls instead:
public class FooOrBar {
private Map<String, Method> methodMap = new HashMap<String, Method>();
public FooOrBar() {
try {
methodMap.put("foo", this.getClass().getMethod("doFoo", new Class[0]));
methodMap.put("bar", this.getClass().getMethod("doBar", new Class[0]));
} catch (NoSuchMethodException n) {
throw new RuntimeException(n);
}
}
public void doSomething(String str) {
Method m = methodMap.get(str);
try {
m.invoke(this, null);
} catch (Exception n) {
throw new RuntimeException(n);
}
}
public void doFoo() {
System.out.println("foo");
}
public void doBar() {
System.out.println("bar");
}
public static void main(String[] args) {
FooOrBar fb = new FooOrBar();
fb.doSomething("foo");
}
}
Abuse the ternary operator, at least in C#:
Action result =
s == "bar" ? (Action)(() => { Console.WriteLine("bar"); }):
s == "foo" ? (Action)(() => { Console.WriteLine("foo"); }) :
(Action)(() => { Console.WriteLine(); });
Actually, I take that back... never EVER do this. Use a switch.
I read http://www.antiifcampaign.com/articles/the-simplest-anti-if-code.html and I think that the medicine is worse than the disease. Much, much worse. You required to invest up front in some heavy OO machinery to solve a possible (improbable?) future problem.
A little late to the party, but combining the C# dictionary answers from MRFerocius and cletus gives the following implementation of bmargulies's answer:
private Dictionary<string,Action> data = new Dictionary<string, Action> {
{"foo", () => Console.WriteLine("Some logic here")},
{"bar", () => Console.WriteLine("something else here")},
{"raboof", () => Console.WriteLine("of course I need more than just WriteLine")},
}
public static void main(String[] args) {
data["foo"]();
}
If the key doesn't exist in the dictionary, using it in the indexer will throw an exception.
Multiple actions can be composed:
There can be multiple calls to different methods, using multiline lambda syntax:
{"foobar", () => {
data["foo"]();
data["bar"]();
}
As Action is a delegate type, multiple methods can be attached to a single delegate instance and that delegate instance set as the value; they will be called sequentially when the delegate is invoked:
public static void main(String[] args) {
data["foobar"] = data["foo"] + data["bar"];
//This will invoke first data["foo"] then data["bar"]
data["foobar"]();
}
For methods not referenced via the dictionary, this can also be done in the collection initializer:
{"foobar", (Action)method1 + method2}
Here goes mine. Using LINQ and Factory Pattern :D
class FactoryString
{
static FactoryString()
{
private static Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{"foo", "some logic here"},
{"bar", "something else here"},
{"raboof", "of course I need more than just Writeln"},
};
}
public static string getString(string s)
{
return dictionary.Single(x => x.Key.Equals(s)).Value;
}
}
static void main()
{
Console.WriteLine(FactoryString.getString("foo"));
}
My general perspective on this kind of problem is not that if statements are bad, it's that it's easier to debug data than it is to debug code.
Here's a non-trivial example from production code. This may look a little complicated at first blush, but at its core it's really simple: depending on the disposition code on a charge row, we need to perform an update to some of its related sentence rows. But we pick different sentence rows, and perform different kinds of updates on them, for different disposition codes.
This is a relatively simple example - there are only five disposition codes, two tests, and two types of updates. Even so, this is vastly simpler than what it replaced. Also, it's a lot easier to tell just from looking at the code that it does what the requirements say it should do, since the mappings in the code correspond to tables in the requirements document. (Before I wrote this code, I had to rewrite the requirements document so that this stuff was all defined in a table. The original code was a mess because the requirements were a mess too. Rewriting the requirements to make them clearer exposed bugs in the requirements, too.)
It's worth emphasizing that it's pretty easy to write a unit test that covers 100% of this code. It's also worth emphasizing that the complexity of this code scales linearly with the number of disposition codes, predicates, and updates that it supports; if case or if statements were used, it would scale exponentially.
/// <summary>
/// Update a sentence's status to Completed [401110]
/// </summary>
/// <param name="senRow"></param>
/// <param name="eventDate"></param>
private static void CompleteSentence(DataRow senRow, DateTime eventDate)
{
senRow.SetField("SenStatus", "401110");
senRow.SetField("SenStatusDate", eventDate);
}
/// <summary>
/// Update a sentence's status to Terminated [401120]
/// </summary>
/// <param name="senRow"></param>
/// <param name="eventDate"></param>
private static void TerminateSentence(DataRow senRow, DateTime eventDate)
{
senRow.SetField("SenStatus", "401120");
senRow.SetField("SenStatusDate", eventDate);
}
/// <summary>
/// Returns true if a sentence is a DEJ sentence.
/// </summary>
/// <param name="senRow"></param>
/// <returns></returns>
private static bool DEJSentence(DataRow senRow)
{
return Api.ParseCode(senRow.Field<string>("SenType")) == "431320";
}
/// <summary>
/// Returns true if a sentence is a Diversion sentence.
/// </summary>
/// <param name="senRow"></param>
/// <returns></returns>
private static bool DiversionSentence(DataRow senRow)
{
return Api.ParseCode(senRow.Field<string>("SenType")).StartsWith("43");
}
/// <summary>
/// These are predicates that test a sentence row to see if it should be updated
/// if it lives under a charge disposed with the specified disposition type.
///
/// For instance, if the PDDispositionCode is 413320, any DEJ sentence under the
/// charge should be updated.
/// </summary>
private static readonly Dictionary<string, Func<DataRow, bool>> PDSentenceTests =
new Dictionary<string, Func<DataRow, bool>>
{
{"411610", DiversionSentence}, // diversion successful
{"413320", DEJSentence}, // DEJ successful
{"442110", DiversionSentence}, // diversion unsuccessful
{"442111", DiversionSentence}, // diversion unsuccessful
{"442112", DiversionSentence}, // diversion unsuccessful
{"442120", DEJSentence} // DEJ unsuccessful
};
/// <summary>
/// These are the update actions that are applied to the sentence rows which pass the
/// sentence test for the specified disposition type.
///
/// For instance, if the PDDispositionCode is 442110, sentences that pass the sentence
/// test should be terminated.
/// </summary>
private static readonly Dictionary<string, Action<DataRow, DateTime>> PDSentenceUpdates =
new Dictionary<string, Action<DataRow, DateTime>>
{
{"411610", CompleteSentence}, // diversion successful (completed)
{"413320", CompleteSentence}, // DEJ successful (completed)
{"442110", TerminateSentence}, // diversion unsuccessful (terminated)
{"442111", TerminateSentence}, // diversion unsuccessful (terminated)
{"442112", TerminateSentence}, // diversion unsuccessful (terminated)
{"442120", TerminateSentence} // DEJ unsuccessful (terminated)
};
private void PDUpdateSentencesFromNewDisposition()
{
foreach (DataRow chargeRow in PDChargeRows
.Where(x => PDSentenceTests.ContainsKey(x.Field<string>("PDDispositionCode"))))
{
string disp = chargeRow.Field<string>("PDDispositionCode");
foreach (DataRow s in CHGRows[chargeRow]
.ChildRows("CAS-SUBCRM-CHG-SEN")
.Where(x => PDSentenceTests[disp](x)))
{
PDSentenceUpdates[disp](s, EventDate);
}
}
}