Java и избегать операторов if для объектов с похожими методами - PullRequest
1 голос
/ 19 октября 2011

У меня есть 2 класса, например А и Б.
Эти классы имеют несколько методов получения / установки с одинаковым именем.

Теперь в коде я делаю следующее:

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();
}

Мне было интересно, есть ли способ вызвать getInfo, избегая операторов if.
Примечание: Я не могу реорганизовать классы для использования наследования или чего-то еще.
Мне было просто интересно, есть ли хитрость в java, чтобы избежать операторов if.

Ответы [ 8 ]

6 голосов
/ 19 октября 2011

Если вы не хотите использовать отражение, нет. Java обрабатывает два типа, которые случаются , чтобы объявить один и тот же метод (getInfo()) как полностью отдельные, с совершенно отдельными методами.

Если у вас есть общность, вы должны использовать общий суперкласс или общий интерфейс, который они оба наследуют. Вы пометили вопрос «дизайн-шаблоны» - шаблон должен использовать инструменты, предоставляемые языком, чтобы показать общность.

Как показывает Eng.Fouad, использование instanceof в любом случае проще - и лучше, поскольку это означает, что ваш код будет по-прежнему работать с подклассами A или B.

Вы можете изолировать это уродство, конечно, поместив его в одном месте - либо с классом фасада, который может быть построен из A или B, либо с помощью один метод, который выполняет эту проверку, а затем вызывает ее из нескольких мест.

1 голос
/ 01 декабря 2011

Если obj объявлен как A или B, вы можете использовать перегруженные методы. (Хороший аргумент для безопасности типов.) Вот тест, который иллюстрирует это:

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
    }
}
1 голос
/ 19 октября 2011

Вам нужно Отражение .Вот мой полный пример.

Класс 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;
        }
    }

Класс 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;
    }
}

ТестКласс

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();
        }
    }
}

См. Эту строку:

Class c = obj.getClass();

и

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

и

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

Нет if заявлений

1 голос
/ 19 октября 2011

Если вы не можете использовать наследование и хотите избежать операторов if (даже используя instanceof) ... ну ... лучшее, что вы можете сделать, это обернуть проверку, приведение и вызов функции, чтобы избежатьдублирование кода ... в противном случае это невозможно.

0 голосов
/ 19 октября 2011

В Java вы можете использовать точку в качестве оператора разрешения области действия со статическими методами. Попробуйте что-то вроде этого:

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

С объектами, если два интерфейса действительно имеют один и тот же метод с одинаковыми параметрами и одинаковым типом возврата, почему они должны обрабатываться по-разному? Взгляните здесь для более глубокого понимания проблемы.

Удачи.

0 голосов
/ 19 октября 2011

Если obj - Объект, вам нужно проверить.Если вы не хотите использовать оператор if, вы можете просто выполнить приведение и поймать исключение:

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

Еще одна вещь, которую вы можете сделать - заставить оба класса реализовать интерфейс, а затем проверить только этот интерфейс, что-то вроде:

public interface HasInfo
{
    public String getInfo();
}

Затем добавьте implements HasInfo в определение класса для A и B. Затем вы можете просто проверить (или привести) к HasInfo.

0 голосов
/ 19 октября 2011

Обратитесь к: этому руководству , если это то, чего вы пытались достичь.

0 голосов
/ 19 октября 2011

Как насчет:

String result = null;

if(obj instanceof A)
{
    result = ((A) obj).getInfo();
}
else if(obj instanceof B)
{
    result = ((B) obj).getInfo();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...