从方法返回接口对象而不实例化(未知)具体类型

时间:2016-03-30 18:34:19

标签: java design-patterns interface polymorphism

我确信这有一些解决方案或模式,但我无法明确表达问题以找到正确的答案。

我有一个界面,ICar:

public interface ICar {
void SetMake(String make);
String GetMake();
}

我有一节课,Car:

public class Car implements ICar {
private String make;

public void SetMake(String make) { this.make = make; }

public String GetMake() { return make; }

我在另一个课程中有一个方法,它不知道Car。本着多态性的精神,我想让这个方法返回一个ICar,这样有人就可以创建自己的ICar实现并将这个方法用于他们的汽车:

...//class preamble
public ICar myMethod() {
    ICar myCar = new ICar();
    myCar.SetMake("Ferrari");
    return myCar;
}

我不确定为什么这样的事情无法奏效。由于ICar包含SetMake方法,因此每个实现都必须包含此方法。当然,jvm可以以某种方式排队方法调用,然后在方法的具体结果可用时运行它们吗?

另一个想法是将新创建的ICar实现作为参数传递给myMethod并调用其方法,但我觉得这可能不是一个干净的实现,因为我每次都需要创建一个Car实例。此外,如果没有无参数构造函数,我将不得不使用虚拟数据实例化它(也不干净)。

我觉得我对如何实现这样的事情缺乏一些了解,并且想知道是否有人可以提供帮助?

感谢。

6 个答案:

答案 0 :(得分:1)

这样做的一种方法是将类类型作为参数提供,并使其通用:

public <T extends ICar> T myMethod(Class<T> type) {
    try {
        T myCar = type.newInstance(); // T needs a visible no-args constructor
        myCar.SetMake("Ferrari");
        return myCar;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

(另请注意,我通过在RuntimeException中包装任何内容来处理异常)

然后你需要这样称呼它:

Car car = myMethod(Car.class);

更灵活的方法是引入工厂接口并将工厂实例传递给myMethodICar使用它来创建具体的public interface ICarFactory<T extends ICar> { T createCar(); } ... public <T extends ICar> T myMethod(ICarFactory<T> factory) { T myCar = factory.createCar(); myCar.SetMake("Ferrari"); return myCar; } ... Car car = myMethod(carFactory); 。工厂仍然是通用的:

/>

答案 1 :(得分:0)

你需要这样做:

public ICar myMethod() {
    ICar myCar = new Car();
    myCar.SetMake("Ferrari");
    return myCar;
}

而不是

public ICar myMethod() {
    ICar myCar = new ICar();
    myCar.SetMake("Ferrari");
    myCar.return;
}

这句话:myCar.return;在这里几乎没有意义......因为ICar是一个你不能做的界面ICar myCar = new ICar()

答案 2 :(得分:0)

您无法实例化接口,因此new ICar()不是一个选项。例如,setMake应该设置一个实例变量,但是Interface没有实例变量。

但是,您可以执行以下操作:

        return new ICar() {
        String m;
        @Override
        public void setMake(String make)
        {
            m = make;
        }



        @Override
        public String getMake()
        {
            return m;
        }
    };

通过这种方式,您将创建一个实现接口的对象。

虽然这个答案提供了一个回答问题的特定示例(就像简单地实例化Car对象一样),但是关于接口的更大问题是可以返回在接口中实现的任何Object。除了允许委托创建对象之外,还有许多设计模式。例如,人们可能会考虑Factory Pattern

答案 3 :(得分:0)

您无法创建新界面,但可以返回一个。

public ICar myMethod() {
    ICar myCar = new Car();
    myCar.SetMake("Ferrari");
    return myCar;
}

接口是指它基本上说的合同#34;这是一个ICar它可以是CarRedCar和一千种不同的实现,但你不会#39知道哪个&#34; 。 这就是多态的含义,无论谁使用myMethod都不知道他得到了哪辆车,他只能知道contract而不知道它们是如何实现的。

答案 4 :(得分:0)

我不确定我是否完全了解你的内容,但我认为你真正想做的是从抽象基类继承你的Car,以便其他人可以实现其他类型的工具。

这样的事情:

public abstract class Vehicle {
    public abstract void SetMake(String make);
    public abstract String GetMake();
}

public class Car extends Vehicle {
    private String make;
    public void SetMake(String make) { this.make = make; }
    public String GetMake() { return make; }
}

public class Truck extends Vehicle {
    private String make;
    public void SetMake(String make) { this.make = make; }
    public String GetMake() { return make; }
}



public Vehicle myMethod() {
    Vehicle myCar = new Truck();
    myCar.SetMake("Ferrari");
    return myCar;
}    

答案 5 :(得分:0)

对于您已声明的方法myMethod()

  

“本着多态性的精神,我希望这种方法能够返回一个ICar,这样有人就可以创建自己的ICar实现并将这种方法用于他们的汽车:”

我从中理解的是,您希望myMethod()使用不同具体类型的ICar

使用new operator时会创建对象。您现有的代码无法编译,因为您无法实例化Interfaces的对象。为了解决编译错误,我不希望你创建具体的汽车对象:

ICar car = new Car(); // this will solve compile error but avoid doing this in your code
  

避免使用new运算符,让代码的用户使用new并注入具体实现(您可能甚至不知道具体实现,因为它们是依赖于用户的代码用户)。

更改方法如下

...//class preamble
public ICar myMethod(ICar myCar, String make) {
    myCar.SetMake(make);
    return myCar;
}

我建议你学习:DIP principledependency injectioncode to interface