Cratylus
Cratylus

Reputation: 54094

Java and avoid if statements for objects with similar methods

I have 2 classes e.g. A and B.
These classes have a couple of getter/setter methods with the same name.

Now in the code I do the following:

if(obj.getClassName().equals(A.class.getName())){
   A a = (A) obj;
   String result = a.getInfo();
}
else if(obj.getClassName().equals(B.class.getName())){
   B a = (B) obj;
   String result = a.getInfo();
}

I was wondering if there is a way to call the getInfo avoiding the if statements.
Note: I can not refactor the classes to use inheritence or something else.
I was just interested if there is a trick in java to avoid the if statements.

Upvotes: 1

Views: 1290

Answers (8)

Brian T. Forsythe
Brian T. Forsythe

Reputation: 11

If obj is declared as either A or B, you can use overloaded methods. (A good argument for type safety.) Here's a test that illustrates this:

import static org.junit.Assert.*;

import org.junit.Test;

public class FooTest {

    class A {
        public String getInfo() {
            return "A";
        }
    }

    class B {
        public String getInfo() {
            return "B";
        }
    }

    public String doBarFor(A a) {
        return a.getInfo();
    }

    public String doBarFor(B b) {
        return b.getInfo();
    }

    public String doBarFor(Object obj) {
        throw new UnsupportedOperationException();
    }

    @Test
    public void shouldDoBarForA() {
        A a = new A();
        assertEquals("A", doBarFor(a));
    }

    @Test
    public void shouldDoBarForB() {
        B b = new B();
        assertEquals("B", doBarFor(b));
    }

    @Test(expected = UnsupportedOperationException.class)
    public void shouldFailIfDeclaredAsObject() {
        Object a = new A();
        assertEquals("A", doBarFor(a)); // exception thrown
    }
}

Upvotes: 1

gtiwari333
gtiwari333

Reputation: 25174

You need reflection. here is my complete example.

Class A

 package a;
    public class A {
        String info;
        public String getInfo() {
            System.out.println("A getInfo");
            return info;
        }
        public void setInfo(String info) {
            this.info = info;
        }
    }

Class B

package a;
public class B {
    String info;
    public String getInfo() {
        System.out.println("B getInfo");
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

Test Class

package a;
import java.lang.reflect.Method;
public class TestAB {
    public static void main(String[] args) {
        A a= new A();
        doSth(a);
    }
    private static void doSth(Object obj) {
        Class c = obj.getClass();
        Method m;
        try {
            m = c.getMethod("getInfo", new Class[] { });
            String result = (String) m.invoke(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

See this line :

Class c = obj.getClass();

and

m = c.getMethod("getInfo", new Class[] { });

and

String result = (String) m.invoke(obj);

There is no if statements

Upvotes: 1

Randall Cook
Randall Cook

Reputation: 6776

In Java you can use a dot as a scope resolution operator with static methods. Try something like this:

String a_info = A.getInfo();
String b_info = B.getInfo();

With objects, if two interfaces really have the same method with the same parameters and the same return type, why must they be treated differently? Take a look here for some more insight into the problem.

Good luck.

Upvotes: 0

Jon Lin
Jon Lin

Reputation: 143966

If obj is an Object, you'll need to check. If you don't want to use an if-statement, you can try just casting and catch the exception:

String result = null;
try {
    result = ((A)obj).getInfo();
}
catch(ClassCastException e1) {
    try {
        result = ((B)obj).getInfo();
    }
    catch(ClassCastException e2) {
         // do something else
    }
}

Another thing you can do is make both classes implement an Interface then check for just that Interface, something like:

public interface HasInfo
{
    public String getInfo();
}

Then add implements HasInfo in the class definition for A and B. Then you can just check (or cast) to HasInfo.

Upvotes: 0

Amanpreet
Amanpreet

Reputation: 526

Refer to : this tutorial if this is what you were trying to achieve.

Upvotes: 0

Luchian Grigore
Luchian Grigore

Reputation: 258678

If you can't use inheritance and want to avoid if statements (even using instanceof)... well... the best you can do is wrap the check, cast and call in a function to avoid code duplication... otherwise there's no way to do this.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1503799

Unless you want to use reflection, no. Java treats two types which happen to declare the same method (getInfo()) as entirely separate, with entirely separate methods.

If you've got commonality, you should be using a common superclass or a common interface that both of them inherit. You've tagged the question "design-patterns" - the pattern is to use the tools that the language provides to show commonality.

As Eng.Fouad shows, using instanceof is simpler anyway - and better, as it means your code will still work with subclasses of A or B.

You can isolate this ugliness, of course, by putting it in a single place - either with a facade class which can be constructed from either an A or a B, or by having a single method which performs this check, and then calling that from multiple places.

Upvotes: 6

Eng.Fouad
Eng.Fouad

Reputation: 117675

How about:

String result = null;

if(obj instanceof A)
{
    result = ((A) obj).getInfo();
}
else if(obj instanceof B)
{
    result = ((B) obj).getInfo();
}

Upvotes: 0

Related Questions