具有可变参数类型的接口方法

Bojan Vukasovic:

我有调用相似行为时需要不同参数的Java接口和类实现。以下哪项最合适?

在第一个选项中,我有不同的类从基本接口继承相同的行为,并且所有差异仅在类中直接实现,而不在接口中实现。这似乎最合适,但是我必须在代码中进行手动类型转换。

public class VaryParam1 {

    static Map<VehicleType, Vehicle> list = new HashMap<>();

    static List<Car> carsList = new ArrayList<>();
    static List<TruckWithTrailer> trucksList = new ArrayList<>();

    public static void main(String[] args) {
        list.put(VehicleType.WITHOUT_TRAILER, new Car());
        list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());

        //violates LSP?
        ((Car)list.get(VehicleType.WITHOUT_TRAILER)).paint(1); //ok - but needed manual cast
        ((TruckWithTrailer)list.get(VehicleType.WITH_TRAILER)).paint(1, "1"); //ok - but needed manual cast

        carsList.add(new Car());
        trucksList.add(new TruckWithTrailer());

        //Does not violate LSP
        carsList.get(0).paint(1);
        trucksList.get(0).paint(1, "1");
    }
}

enum VehicleType {
    WITHOUT_TRAILER,
    WITH_TRAILER;
}

interface Vehicle{
    //definition of all common methods
    void drive();
    void stop();
}

class Car implements Vehicle {

    public void paint(int vehicleColor) {
        System.out.println(vehicleColor);
    }

    @Override
    public void drive() {}

    @Override
    public void stop() {}
}

class TruckWithTrailer implements Vehicle {

    public void paint(int vehicleColor, String trailerColor) {
        System.out.println(vehicleColor + trailerColor);
    }

    @Override
    public void drive() {}

    @Override
    public void stop() {}
}

在第二个选项中,我将方法上移到接口的上一级,但是现在我需要使用UnsupportedOpException实现行为。这看起来像代码气味。在代码中,我不必手动进行强制转换,但是我也有可能调用在运行时会产生异常的方法,而无需进行编译时检查。这不是什么大问题-只有这种看起来像代码气味的异常方法。这种实施方式是最佳实践吗?

public class VaryParam2 {

    static Map<VehicleType, Vehicle> list = new HashMap<>();

    public static void main(String[] args) {
        list.put(VehicleType.WITHOUT_TRAILER, new Car());
        list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());

        list.get(VehicleType.WITHOUT_TRAILER).paint(1); //works
        list.get(VehicleType.WITH_TRAILER).paint(1, "1"); //works

        list.get(VehicleType.WITHOUT_TRAILER).paint(1, "1"); //ok - exception - passing trailer when no trailer - no compile time check!
        list.get(VehicleType.WITH_TRAILER).paint(1); //ok - exception - calling trailer without trailer args - no compile time check!
    }
}

enum VehicleType {
    WITHOUT_TRAILER,
    WITH_TRAILER;
}

interface Vehicle{
    void paint(int vehicleColor);
    void paint(int vehicleColor, String trailerColor);    //code smell - not valid for all vehicles??
}

class Car implements Vehicle {

    @Override
    public void paint(int vehicleColor) {
        System.out.println(vehicleColor);
    }

    @Override
    public void paint(int vehicleColor, String trailerColor) {    //code smell ??
        throw new UnsupportedOperationException("Car has no trailer");
    }
}

class TruckWithTrailer implements Vehicle {

    @Override
    public void paint(int vehicleColor) {  //code smell ??
        throw new UnsupportedOperationException("What to do with the trailer?");
    }

    @Override
    public void paint(int vehicleColor, String trailerColor) {
        System.out.println(vehicleColor + trailerColor);
    }
}

在这里,我使用泛型以便在接口中具有通用方法,并且在每个类的实现中确定参数类型。这里的问题是我未选中绘画请求。这更类似于选项1中的直接转换问题。Bur在这里,我也有可能调用我不应该使用的方法!

public class VaryParam3 {

    static Map<VehicleType, Vehicle> list = new HashMap<>();


    public static void main(String[] args) {
        list.put(VehicleType.WITHOUT_TRAILER, new Car());
        list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());

        list.get(VehicleType.WITHOUT_TRAILER).paint(new VehicleParam());    //works but unchecked call
        list.get(VehicleType.WITH_TRAILER).paint(new TruckWithTrailerParam());    //works but unchecked call

        list.get(VehicleType.WITHOUT_TRAILER).paint(new TruckWithTrailerParam()); //works but should not!
        list.get(VehicleType.WITH_TRAILER).paint(new VehicleParam());   //ClassCastException in runtime - ok but no compile time check
    }
}

enum VehicleType {
    WITHOUT_TRAILER,
    WITH_TRAILER;
}

class VehicleParam {
    int vehicleColor;
}

class TruckWithTrailerParam extends VehicleParam {
    String trailerColor;
}

interface Vehicle<T extends VehicleParam>{
    void paint(T param);
}

class Car implements Vehicle<VehicleParam> {

    @Override
    public void paint(VehicleParam param) {
        System.out.println(param.vehicleColor);
    }
}

class TruckWithTrailer implements Vehicle<TruckWithTrailerParam> {

    @Override
    public void paint(TruckWithTrailerParam param) {
        System.out.println(param.vehicleColor + param.trailerColor);
    }
}

所以问题是-这3个选项中哪一个是最好的(或者是否还有我找不到的其他选项)?在进一步维护,更改等方面

更新

我更新了问题,现在有了paint方法,只有在构造对象之后才能调用它。

到目前为止,这似乎是最好的选择,如以下文章中所建议:

public class VaryParam4 {

    static Map<VehicleType, Vehicle> list = new HashMap<>();

    public static void main(String[] args) {
        list.put(VehicleType.WITHOUT_TRAILER, new Car());
        list.put(VehicleType.WITH_TRAILER, new TruckWithTrailer());

        list.get(VehicleType.WITHOUT_TRAILER).paint(new PaintConfigObject());    //works but can pass trailerColor (even if null) that is not needed
        list.get(VehicleType.WITH_TRAILER).paint(new PaintConfigObject());    //works
    }
}

enum VehicleType {
    WITHOUT_TRAILER,
    WITH_TRAILER;
}

class PaintConfigObject {
    int vehicleColor;
    String trailerColor;
}

interface Vehicle{
    void paint(PaintConfigObject param);
}

class Car implements Vehicle {

    @Override
    public void paint(PaintConfigObject param) {
        //param.trailerColor will never be used here but it's passed in param
        System.out.println(param.vehicleColor);
    }
}

class TruckWithTrailer implements Vehicle {

    @Override
    public void paint(PaintConfigObject param) {
        System.out.println(param.vehicleColor + param.trailerColor);
    }
}
CKing:

更好的选择是摆脱方法的重载版本,drive并传递构造函数中子类所需的所有信息:

interface Vehicle{
    void drive();
}

class Car implements Vehicle {
    private int numberOfDoors;

    public Car(int numberOfDoors) {
         this.numberOfDoors = numberOfDoors;
     }

    public void drive() {
        System.out.println(numberOfDoors);
    }
}


class TruckWithTrailer implements Vehicle {
    private int numberOfDoors;
    private int numberOfTrailers;

    public TruckWithTrailer(int numberOfDoors,numberOfTrailers) {
          this.numberOfDoors = numberOfDoors;
          this.numberOfTrailers = numberOfTrailers;
    }

    @Override
    public void drive() {
        System.out.println(numberOfDoors + numberOfTrailers);
    }
}

解决您关于paint在运行时确定问题的评论,您可以paint向车辆添加一个采用可变参数的方法:

interface Vehicle{
    void drive();
    void paint(String ...colors);
}

如评论中所述,如果在paint方法中使用的参数数量因不同的车辆类型而异,则定义一个名为的类PaintSpecification,其中包含诸如之类的属性vehcileColortrailerColor然后将paint方法更改为具有type的参数PaintSpecification

interface Vehicle{
    void drive();
    void paint(PaintSpecification spec);
}

上述所有方法的优点在于,所有Vehicle实现都遵循一个协定,从而使您可以执行操作,例如将所有Vehicle实例添加到,Listpaint对其一个一个地调用它们方法,而不管它们的类型如何。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

C ++创建具有可变参数模板方法的接口

具有泛型接口参数类型的Java通用方法

具有可变参数类型参数的可变函数

具有可变参数类型的模板多个可变参数继承

具有可变参数类型的函数

具有可变类型参数的泛型

具有可变模板类型的DescribeFunction参数

将未知的枚举类型传递给具有可变参数枚举参数的方法

具有可变参数列表的方法

如何拥有具有不同数量和类型参数的接口方法?C#

具有多种返回类型的接口方法

具有通用类型的接口和方法

有什么方法可以将成对的元组剥离为可变参数模板类型或实例化具有可变参数类型的对象?

为什么允许具有不同交集类型参数的接口方法实现?

具有不同类型的可变参数的宏

如何创建具有可变数量的类型参数的模板?

具有可变参数计数的函数的TypeScript类型签名

如何具有类型和大小的可变参数模板?

具有可变类型参数的多线程函数

具有可变参数化和类型的C函数指针

具有混合类型参数和非类型可变参数的模板模板参数

具有类型或接口的TypeScript分解的默认参数

.NET Core Cast与具有实现接口的类型的通用类型参数的接口

向下转换在Java +调用方法具有可变参数

使此方法具有可变参数泛型

具有可变参数列表的抽象方法

具有默认和可变长度参数的实例方法

具有可变参数数组的phpUnit测试方法

具有不同子类型的参数方法