Методы, которые возвращают интерфейс? [учитывая, что существует много реализаций интерфейса] - PullRequest
0 голосов
/ 18 марта 2012

Этот вопрос может быть простым (я бы хотел, чтобы это не так), но я нашел его в интервью.В целом, с учетом класса интерфейса IntClass и ряда классов, реализует интерфейс с именем ImpIC1, ImpIC2, ..., ImpICk.Методы в IntClass являются абстрактными открытыми методами с именами void action1 (), void action2 () ..., void actionM ().

Мне дали открытый класс Test с общедоступной статической функцией с именем: public static IntClass foo (IntClass c1, IntClass c2).Этот метод выполняет некоторые операции на c1 и c2 для создания InClass и возвращает. Однако метод должен работать для каждой действительной реализации IntClass .Проблема в основном с определением с3.Как бы я разработал метод foo () ..

, см. Ниже детали кода:

public interface IntClass { 
 abstract void action1(); 
 .. 
 abstract void actionM();
 }

..

 public class ImpIC1 implements IntClass { 
 public void action1() { ... } 
 public void action2() { ....}
 ..
 public void actionM() { ... } 
 } 

...

 public class ImpIC2 implements IntClass { 
 public void action1() { ... } 
 public void action2() { ....}
 ..
 public void actionM() { ... } 
 } 

...

 public class ImpICk implements IntClass { 
 public void action1() { ... } 
 public void action2() { ....}
 ..
 public void actionM() { ... } 
 }    

...

public class Test { 
public static IntClass foo(IntClass c1, IntClass c2) { 
 ....
 ...
  return c3; 
}
} 

...

Проблема в основном с определением c3.Я попробовал следующие решения (ни одно из которых не работает):

  1. внутри foo, c3 был определен как экземпляр Object .. т.е. IntClass c3 = (IntClass) new Object ().- ошибка времени компиляции Объект не может быть приведен к IntClass
  2. внутри foo, c3 остался без инициализации.(ошибка времени компиляции).
  3. внутри foo, c3 - ноль, (исключение нулевого указателя)
  4. внутри foo, c3 инициализируется как одна из реализаций c3 (т.е. c3 = (IntClass)new ImpIC1 ()) .. проблема в том, что если мы выполняем во внешнем ImpIC2 s = (ImpIC1) foo (c1, c2) - мы получаем ошибку (невозможно привести).

Ответы [ 5 ]

1 голос
/ 18 марта 2012

Опубликованные спецификации крайне расплывчаты. Msgstr "Этот метод выполняет некоторые операции на c1 и c2 для создания InClass и возвращает". Это вовсе не определяет ЛЮБЫЕ функциональные требования.

Следующее решение выполняет некоторые операции над c1 и c2 (это довольно бессмысленные операции, но спецификации не запрещают этим операциям быть бессмысленными). Он также создает новый экземпляр IntClass, который возвращается. И любая реализация IntClass может быть передана в качестве параметра, и метод все равно будет работать.

public static IntClass foo(IntClass c1, IntClass c2){
    c1.getClass();
    c2.toString();
    return new IntClass{
            public void action1(){}
            public void action2(){}
            ...
            public void actionM(){}
        };
}

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

public class Test{

    public static IntClass foo(IntClass c1, IntClass c2){
        return new CompositeIntClass(c1, c2);
    }

    public class CompositeIntClass implements IntClass{
        private IntClass c1;
        private IntClass c2;

        public CompositeIntClass(IntClass c1, IntClass c2){
            this.c1 = c1;
            this.c2 = c2;
        }

        public void action1(){
            c1.action1();
            c2.action1();
        }

        public void action2(){
            c1.action2();
            c2.action2();
        }

        ...

        public void actionM(){
            c1.actionM();
            c2.actionM();
        }
    }
}

Используя эту реализацию, вызов foo (c1, c2) формально не будет выполнять никаких операций с c1 или c2. Таким образом, он не удовлетворяет заявленным требованиям. Тем не менее, он создаст новый экземпляр IntClass, который будет сочетать поведение c1 и c2. То есть вызов action2 () для c3 вызовет action2 () для c1 и c2. Я думаю, что это могут быть те требования, которые должны были быть (только предположение).

Таким образом, в общем, это означает, что возвращаемый объект (c3) будет иметь поведение любых произвольных реализаций IntClass. Это, однако, не будет означать, что вы сможете сделать SomeArbitraryImplClass c3 = (SomeArbitraryImplClass) foo(c1, c2);, потому что это будет нарушением всей концепции абстракции интерфейса (безусловно, ничего, что будет рекомендовано в интервью).

Решение является примером Составной паттерн .

Если вы используете обобщенные абстракции, вы должны убедиться, что они совместимы с проблемами, которые вы собираетесь решать с ними. Поскольку все методы actionI () в описанном параметре проблемы имеют возвращаемый тип void, невозможно извлечь min и max любого экземпляра PairInterface (как описано в вашем комментарии). Абстракция не позволяет этого.

Если это то, что вы хотите сделать, решение намного проще. (Это основано на предположении, что PairInterface содержит объявления int getX() и int getY(), что кажется разумным для PairInterface):

public class Test{
    public static PairInterface mix(PairInterface c1, PairInterface c2){
        int minX = Math.min(c1.getX(), c2.getX());
        int maxY = Math.max(c1.getY(), c2.getY());
        return new SomePairInterfaceImplementation(minX, maxY);
    }
}

Наряду с этим вам также необходимо создать класс SomePairInterfaceImplementation или использовать какой-нибудь существующий класс, который может принимать x и y в качестве параметров конструктора.

Обратите внимание, что:

1) Если PairInterface объявляет только пустые методы, НЕВОЗМОЖНО определить максимальные или минимальные значения x для c1 и c2. Значения инкапсулированы и скрыты и недоступны.

2) Не должно иметь значения, какую реализацию PairInterface возвращает метод. Причиной наличия возвращаемого типа интерфейса является то, что любая согласованная реализация интерфейса должна работать.

1 голос
/ 18 марта 2012

Возможно, они хотели узнать, знаете ли вы, как использовать отражение , чтобы возвратить экземпляр любого класса c1.Каждый объект является экземпляром класса (даже анонимных внутренних классов).Вы можете дать интерфейс для типа ссылки, но в конце он указывает на экземпляр class .

public IntClass foo(IntClass c1, IntClass c2) {
    IntClass c3 = c1.getClass().newInstance(); // requires no-arg constructor
    // use c1 and c2 to set up c3 ...
    return c3;
}
1 голос
/ 18 марта 2012

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

     public class Test { 
            public static IntClass foo(IntClass c1, IntClass c2,String className) { 
 ....
 ...

 IntClass c3 = Class.forName(className);
  //Set properties of c3 as your logic.
  return c3; 

} }

0 голосов
/ 18 марта 2012

Вы уверены, что правильно поняли вопрос? Из вашего комментария к Eng.Fouad

ImpClass3 s3 = foo(s1, s2)

Это не имеет смысла. Неправильно иметь что-то абстрактное справа и что-то конкретное слева, обычно это наоборот. Это как если бы вы заказали «что-нибудь поесть, что угодно», но ожидаете именно «Биг Мак Курица с колой»:)

0 голосов
/ 18 марта 2012

Вы можете создать объект интерфейса с помощью анонимного класса и реализовать все абстрактные методы:

IntClass c3 = new IntClass()
{
    @Override
    public void action1()
    {
        // ...
    }

    // ...

    @Override
    public void actionM()
    {
        // ...
    }

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