Вопросы интерфейса - PullRequest
       16

Вопросы интерфейса

4 голосов
/ 01 октября 2008

Предположим, что у меня есть интерфейс MyInterface и 2 класса A, B, которые реализуют MyInterface.
Я объявил 2 объекта: MyInterface a = new A() и MyInterface b = new B().
Когда я пытаюсь перейти к функции - функции doSomething(A a){}, я получаю сообщение об ошибке.

Это мой код:

public interface MyInterface {}

public class A implements MyInterface{}

public class B implements MyInterface{}

public class Tester {

    public static void main(String[] args){
        MyInterface a = new A();
        MyInterface b = new B();
        test(b);
    }

    public static void test(A a){
        System.out.println("A");
    }

    public static void test(B b){
        System.out.println("B");
    }

}

Моя проблема в том, что я получаю какой-то компонентный интерфейс, который может быть всевозможных классов, и мне нужно написать функцию для каждого класса. Таким образом, один из способов - получить интерфейс и проверить, какой это тип. (экземпляр А)

Я хотел бы знать, как другие решают эту проблему ??

Thx

Ответы [ 10 ]

5 голосов
/ 01 октября 2008

Разве вы не можете просто иметь метод на интерфейсе, который реализует каждый класс? Или у вас нет контроля над интерфейсом?

Это обеспечит как полиморфизм, так и избавит от необходимости определять какие-либо внешние методы. Я полагаю, что это является намерением интерфейса, он позволяет клиенту обрабатывать все классы, реализующие его не специфичным для типа образом.

Если вы не можете добавить интерфейс, тогда вам лучше всего ввести второй интерфейс с соответствующим методом. Если вы не можете редактировать ни интерфейс, ни классы, вам нужен метод, у которого интерфейс является параметром, а затем проверьте конкретный класс. Однако это должно быть последним средством, а скорее подрывает использование интерфейса и связывает метод со всеми реализациями.

3 голосов
/ 01 октября 2008

Звучит так, будто вы ищете что-то вроде этого:

public static void test(MyInterface obj){
  if(obj instanceof A) {
     A tmp = (A)obj;
  } else if(obj instanceof B) {
     B tmp = (B)obj;
  } else {
     //handle error condition
  }
}

Но учтите, что это очень дурной тон и указывает на то, что в вашем дизайне что-то пошло не так. Если у вас нет контроля над интерфейсом, то, как предлагает marcj, добавление второго интерфейса может быть правильным решением. Обратите внимание, что вы можете сделать это, сохранив двоичную совместимость.

2 голосов
/ 01 октября 2008

Мне неясно, что вы на самом деле спрашиваете, но проблема в том, что у вас нет метода, который принимает параметр типа MyInterface. Я не знаю, какой точный синтаксис есть в Java, но вы могли бы сделать что-то вроде if (b это B) {test (b как B)}, но я бы не стал. Если вам нужно, чтобы он был универсальным, тогда используйте тип MyInterface в качестве типа переменной, в противном случае используйте B в качестве типа переменной. Вы побеждаете цель использования интерфейса.

1 голос
/ 20 июня 2012

Используйте только один общедоступный класс / интерфейс в одном .java-файле, иначе он выдаст ошибку. И вызовите объект с именем объекта. Вы объявили два метода только в классе Teater, тогда какова цель объявления класса A, B.

1 голос
/ 01 октября 2008

Я не уверен, что полностью понимаю проблему, но похоже, что одним из способов может быть перемещение методов test () в дочерние классы:

public interface MyInterface {    
    public void test();
}

public class A implements MyInterface{
    public void test() {
        System.out.println("A");
    }
}

public class B implements MyInterface{
    public void test() {
        System.out.println("B");
    }
}

public class Tester {

    public static void main(String[] args){
        MyInterface a = new A();
        MyInterface b = new B();
        b.test();
    }
}

Вы также можете использовать метод toString () и распечатать результат этого. Я не могу точно сказать из вопроса, если ваши требования делают это невозможным.

1 голос
/ 01 октября 2008

Я думаю, что посетитель шаблон дизайна поможет вам здесь. Основная идея состоит в том, чтобы ваши классы (A и B) сами вызывали соответствующий метод, а не пытались решить, какой метод вызывать. Будучи парнем из C #, я надеюсь, что моя Java работает:

public interface Visitable {   
   void accept(Tester tester) 
}

public interface MyInterface implements Visitable {    
}

public class A implements MyInterface{
   public void accept(Tester tester){
       tester.test(this);
   }
}

public class B implements MyInterface{
   public void accept(Tester tester){
       tester.test(this);
   }
}

public class Tester {

    public static void main(String[] args){
        MyInterface a = new A();
        MyInterface b = new B();
        a.accept(this);
        b.accept(this);
    }

    public void test(A a){
        System.out.println("A");
    }

    public void test(B b){
        System.out.println("B");
    }

}
0 голосов
/ 14 мая 2013
public interface MyInterface {}

public class A implements MyInterface{}

public class B implements MyInterface{}

public class Tester {

    public static void main(String[] args){
       MyInterface a = new A();
       MyInterface b = new B();
       test(b); // this is wrong
    }

    public static void test(A a){
        System.out.println("A");
    }

    public static void test(B b){
        System.out.println("B");
    }

}

Вы пытаетесь передать объект, на который ссылается ссылочная переменная MyInterface, методу, определенному с аргументом с его подтипом типа test(B b). Компилятор жалуется здесь, потому что ссылочная переменная MyInterface может ссылаться на любой объект, который является подтипом MyInterface, но не обязательно объектом B. Могут быть ошибки времени выполнения, если это разрешено в Java. Возьмите пример, который сделает концепцию более понятной для вас. Я изменил ваш код для класса B и добавил метод.

public class B implements MyInterface {
    public void onlyBCanInvokeThis() {}

}

Теперь просто измените метод test(B b), как показано ниже:

public static void test(B b){
    b.onlyBCanInvokeThis();
    System.out.println("B");
}

Этот код будет взорван во время выполнения, если это разрешено компилятором:

 MyInterface a = new A();
 // since a is of type A. invoking onlyBCanInvokeThis()
 // inside test() method on a will throw exception.
 test(a); 

Чтобы предотвратить это, компилятор запрещает такие методы вызова методов со ссылкой на суперкласс.


Я не уверен, чего вы пытаетесь достичь, но кажется, что вы хотите достичь полиморфизма во время выполнения. Для этого вам нужно объявить метод в вашем MyInterface и реализовать его в каждом из подклассов. Таким образом, вызов метода будет разрешен во время выполнения на основе типа объекта, а не ссылочного типа.

public interface MyInterface {    
    public void test();
}

public class A implements MyInterface{
    public void test() {
        System.out.println("A");
    }
}

public class B implements MyInterface{
    public void test() {
        System.out.println("B");
    }
}

public class Tester {

    public static void main(String[] args){
        MyInterface a = new A();
        MyInterface b = new B();
        b.test(); // calls B's implementation of test()
    }
}
0 голосов
/ 01 октября 2008

Похоже, вам нужно либо a) использовать полиморфизм, поместив метод на MyInterface и реализовав в A и B, либо b) некоторую комбинацию шаблона проектирования Composite и Visitor. Я бы начал с а) и направился бы к б), когда все становится громоздким.

Мои обширные мысли о посетителе:

http://tech.puredanger.com/2007/07/16/visitor/

0 голосов
/ 01 октября 2008

У вас есть 3 варианта:

  1. Шаблон посетителя; вам нужно будет изменить тип MyInterface, включив в него метод visit(Visitor), где класс Visitor содержит множество методов для посещения каждого подкласса.
  2. Используйте if-else внутри вашего метода test(MyInterface), чтобы проверить между ними
  3. Использовать цепочку. То есть объявляем обработчики ATester, BTester и т. Д., Каждый из которых реализует интерфейс ITester, который имеет метод test(MyInterface). Затем в ATester проверьте, что тип равен A, прежде чем что-то делать. Тогда ваш основной класс Tester может иметь цепочку этих тестеров и передавать каждый экземпляр MyInterface по цепочке, пока он не достигнет ITester, который может с ним справиться. Это в основном превращает блок if-else из 2 в отдельные классы.

Лично я бы пошел на 2 в большинстве ситуаций. В Java отсутствует истинная объектная ориентация. Смирись с этим! Придумывание различных способов обычно затрудняет понимание кода.

0 голосов
/ 01 октября 2008

Я обычно использую абстрактный класс, чтобы обойти эту проблему, например так:

public abstract class Parent {}
public class A extends Parent {...}
public class B extends Parent {...}

Это позволяет передавать родительские объекты в функции, которые принимают A или B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...