关于java:返回Interface的方法? [鉴于有很多接口实现]

Methods that return Interface ? [given that there are many implementations of interface]

这个问题可能很简单(我希望不是),但我在一次采访中找到了。
通常,给定一个接口类IntClass,以及许多实现名为ImpIC1,ImpIC2,...,ImpICk的接口的类。 IntClass中的方法是名为void action1(),void action2()...,void actionM()的抽象公共方法。

我得到了一个公共类Test,其公共静态函数名为:public static IntClass foo(IntClass c1,IntClass c2)。此方法对c1和c2执行一些操作以创建InClass并返回。但是,该方法必须适用于IntClass的每个有效实现。问题主要在于c3的定义。我将如何设计方法foo()..

请参阅下面的代码详情:

1
2
3
4
5
public interface IntClass {
 abstract void action1();
 ..
 abstract void actionM();
 }

..

1
2
3
4
5
6
 public class ImpIC1 implements IntClass {
 public void action1() { ... }
 public void action2() { ....}
 ..
 public void actionM() { ... }
 }

...

1
2
3
4
5
6
 public class ImpIC2 implements IntClass {
 public void action1() { ... }
 public void action2() { ....}
 ..
 public void actionM() { ... }
 }

...

1
2
3
4
5
6
 public class ImpICk implements IntClass {
 public void action1() { ... }
 public void action2() { ....}
 ..
 public void actionM() { ... }
 }

...

1
2
3
4
5
6
7
public class Test {
public static IntClass foo(IntClass c1, IntClass c2) {
 ....
 ...
  return c3;
}
}

...

问题主要在于c3的定义。我尝试了以下解决方案(没有一个工作):

  • 在foo里面,c3被定义为Object的实例..即IntClass c3 =(IntClass)new Object()。 - 编译时错误Object无法强制转换为IntClass
  • 在foo里面,c3没有初始化。 (编译时错误)。
  • 在foo里面,c3为null,(空指针异常)
  • 在foo里面,c3被初始化为c3的实现之一(即c3 =(IntClass)new ImpIC1())..问题是如果我们在外部执行ImpIC2 s =(ImpIC1)foo(c1,c2) - 我们收到错误(无法投射)。

  • 发布的规范非常模糊。"此方法对c1和c2执行一些操作以创建一个InClass并返回"。这根本没有指定任何功能要求。

    以下解决方案对c1和c2执行了一些操作(它们是相当荒谬的操作,但规范并不禁止操作无意义)。它还会创建一个返回的新IntClass实例。并且,IntClass的任何实现都可以作为参数传递,并且该方法仍然可以工作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static IntClass foo(IntClass c1, IntClass c2){
        c1.getClass();
        c2.toString();
        return new IntClass{
                public void action1(){}
                public void action2(){}
                ...
                public void actionM(){}
            };
    }

    现在,基于我对可能需求的猜测,我将提出另一个更明智的解决方案。这并不完全符合规定的要求,但我认为这可能是面试官所寻求的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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相结合。即在c3上调用action2()将在c1和c2上调用action2()。我认为这可能是要求应该是什么(只是猜测)。

    总而言之,这意味着返回的对象(c3)将具有任意IntClass实现的行为。然而,这并不意味着你能够做SomeArbitraryImplClass c3 = (SomeArbitraryImplClass) foo(c1, c2);,因为这样做会违反界面抽象的整个概念(肯定没有在访谈中提倡的内容)。

    解决方案是Composite Pattern的一个示例。

    <编辑>

    如果使用广义抽象,则必须确保它们与您要用它们解决的问题兼容。由于所描述的问题设置中的所有actionI()方法都具有void返回类型,因此无法提取任何PairInterface实例的最小值和最大值(如注释中所述)。抽象不允许这样做。

    如果这是您想要做的,那么解决方案就更简单了。 (这是基于PairInterface包含声明int getX()int getY()的假设,这对于PairInterface来说似乎是合理的):

    1
    2
    3
    4
    5
    6
    7
    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只声明了void方法,那么找出c1和c2的x值的最大值或最小值是不可能的。这些值被封装和隐藏,无法访问。

    2)该方法返回的PairInterface的实现方式无关紧要。具有接口返回类型的原因是接口的任何一致实现都应该起作用。


    也许他们想看看你是否知道如何使用反射来返回c1类的实例。每个对象都是一个类的实例(甚至是匿名的内部类)。您可以为引用类型提供接口,但最后它指向一个类实例。

    1
    2
    3
    4
    5
    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;
    }


    我不知道你的实施。但这里有一点我们需要知道。
    您无法实例化接口(匿名内部类除外)。如果你想让Interface返回更改测试类如下 -

    1
    2
    3
    4
    5
    6
    7
    8
         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;

    }
    }


    你确定你的问题是对的吗?从你的评论到Eng.Fouad

    1
    ImpClass3 s3 = foo(s1, s2)

    这没有意义。在右边有一些抽象的东西,在左边有一些具体的东西是错误的,通常它们反之亦然。这就像你订购"任何吃东西,无论如何"但完全期待"巨无霸鸡肉与可乐":)


    您可以使用匿名类创建接口对象并实现所有抽象方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    IntClass c3 = new IntClass()
    {
        @Override
        public void action1()
        {
            // ...
        }

        // ...

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

    };