Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从方法返回接口对象而不实例化(未知)具体类型_Java_Design Patterns_Interface_Polymorphism - Fatal编程技术网

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

Java 从方法返回接口对象而不实例化(未知)具体类型,java,design-patterns,interface,polymorphism,Java,Design Patterns,Interface,Polymorphism,我肯定有一些解决方案或模式,但我很难清楚地回答这个问题以找到正确的答案 我有一个界面,ICar: public interface ICar { void SetMake(String make); String GetMake(); } 我有一门课,一辆车: public class Car implements ICar { private String make; public void SetMake(String make) { this.make = make; } publi

我肯定有一些解决方案或模式,但我很难清楚地回答这个问题以找到正确的答案

我有一个界面,ICar:

public interface ICar {
void SetMake(String make);
String GetMake();
}
我有一门课,一辆车:

public class Car implements ICar {
private String make;

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

public String GetMake() { return make; }
我在另一个类中有一个方法,它不知道汽车。本着多态性的精神,我希望此方法返回一个ICar,以便有人可以创建自己的ICar实现,并将此方法用于他们的汽车:

...//class preamble
public ICar myMethod() {
    ICar myCar = new ICar();
    myCar.SetMake("Ferrari");
    return myCar;
}
我不知道为什么像这样的东西不起作用。由于ICar包含方法SetMake,因此每个实现也必须包含此方法。当然jvm可以以某种方式将方法调用排队,然后在方法的具体化可用时运行它们

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

我觉得我对如何实现这样的东西缺乏一些理解,我想知道是否有人能提供帮助

谢谢。

您需要执行以下操作:

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

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

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

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



        @Override
        public String getMake()
        {
            return m;
        }
    };
这样,您就可以创建一个实现接口的对象


虽然这个答案给出了一个特定的例子来回答这个问题(就像简单地实例化一个Car对象一样),但是关于接口的更大的问题是,可以返回接口中实现的任何对象。有任意数量的设计模式可用于委托对象的创建。例如,你可以考虑,

你不能创建一个新的界面,但是你可以返回一个。
public ICar myMethod() {
    ICar myCar = new Car();
    myCar.SetMake("Ferrari");
    return myCar;
}
接口意味着一个契约,它基本上是说“这是一个
ICar
它可以是
Car
RedCar
和一千种不同的实现,但你不知道是哪种”。
这就是多态性的含义无论谁使用
myMethod
都不知道他得到的是哪辆车,他只能知道
契约,而不能知道它们是如何实现的。

我不太确定我是否确切理解你的目的,但我想你真正想做的是从一个抽象基类继承你的
车,以便其他人可以实施其他类型的车辆

大概是这样的:

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;
}    
Car car = myMethod(Car.class);

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

本着多态性的精神,我希望此方法返回一个ICar,以便有人可以创建自己的ICar实现,并将此方法用于他们的汽车:

我从中了解到,您希望使
myMethod()
与不同具体类型的
ICar
一起工作

使用
新操作符时会创建对象。现有代码无法编译,因为无法实例化接口的对象。要修复编译错误,我不希望您创建具体的汽车对象:

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原则
依赖项注入
代码到接口
,一种方法是提供类类型作为参数,并使其通用:

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);
    }
}
更灵活的方法是引入工厂接口,并将工厂实例传递给
myMethod
,后者使用它创建具体的
ICar
。工厂仍然可以是通用的:

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);
公共接口ICarFactory{
T createCar();
}
...
公共MYT方法(ICarFactory工厂){
T myCar=factory.createCar();
myCar.SetMake(“法拉利”);
归还我的车;
}
...
汽车=我的方法(汽车工厂);

新ICar()将不会编译,因为它是一个接口。很抱歉,我在myCar.return中出错。但这并不能解决问题,因为myMethod无法知道车辆类型。返回后是否可以将其“转换”为车辆类型?所以我可以调用myMethod,比如:
carnewcar=myMethod()
?@RicketyRick否,该方法返回的是
接口
,而不是特定的类。因此,调用将是
ICar newCar=myMethod()
。通常最好使用接口方法,而不是特定的类实现myMethod不知道具体车型?(除了将新车作为参数传递)@Ricketrick,否,因为
Car
是一个特定的类。更好的方法是使用
接口ICar
,而不是使用特定的类
Car
。然而,我对你使用“类型”这个词的方式做了一些假设,这可能是不正确的。我认为,最好的方法是为myMethod使用工厂模式,返回
ICar
,并允许工厂返回
ICar
的特定/具体实例。的确,可以使用此层次结构,但我仍然会创建接口IVehile,并让myMethod()返回该接口。本例还重复了两个子类中的
字符串make
,可以在基本类中处理。这里的方法仍然将一个编程留给一个特定的实现。这是我唯一能做的