是不是坏模式:确定接口实现的class

Is it a bad pattern: determine class of interface implementation

我有接口

interface Car {
  enum Type { MITSUBISHI, FORD }
  Car.Type getType();

还有两个 类 实现接口

class Mitsubishi implements Car {
  @Override
  Car.Type getType() { return Car.Type.MITSUBISHI; }
}
class Ford implements Car {
  @Override
  Car.Type getType() { return Car.Type.FORD; }
}

并像

一样使用它
List<Car> cars = this.cars;
List<Mitsubishi> mitsubishiCars = cars.stream().filter(c -> c.getType().equals(Car.Type.MITSUBISHI)).collect(Collectors.toList());

问题,这是不是一个坏模式?如果是,那为什么?

一般来说,这似乎是一个糟糕的模式,因为接口 Car 不应该知道谁实现了它,而包含这个 enum Type 会自动获取其潜在实现的知识。

这就是说,这完全取决于您如何使用Car.Type

您很可能希望使用枚举值来确定要执行的指定操作。例如:

//park the car depending on the type
switch (type) {
    case MITSUBISHI:
        //park in a certain way
    case FORD:
        //park in some other way
    //...
}

如果是这样的话,除了知道其实现的接口之外,我至少看到了 2 个其他问题:

  • 每次您有一个新的 Car 实现时,您都需要丰富接口 Car 中的枚举 Type。这可能很烦人
  • Type的值变多时,无论什么流结构(switchif块等)都将变得庞大且难以维护。

如果是这样的话,我宁愿在界面中创建根据汽车类型处理动作的方法。例如:

interface Car {
    void park();
}

class Mitsubishi implements Car {
    @Override
    public void park() {
        //way to park a Mitsubishi
    }
}

如果你只是想使用枚举值在某个时候打印汽车的类型(比如在日志中),那么只需在接口中添加一个 String getType() 方法,return 正确的品牌:

interface Car {
    String getType();
}

class Mitsubishi implements Car {
    @Override
    public String getType() {
        return "Mitsubishi";
    }
}

但总的来说,我不会建议这种方法,除非您没有想到 Car.Type 的用途,但您没有分享(尽管我真的不知道您还可以如何使用除了我上面列出的 2 种情况外,我想使用枚举。

Post-编辑

看到您想如何使用枚举后:

List<Car> cars = this.cars;
List<Mitsubishi> mitsubishiCars = cars.stream()
    .filter(c -> c.getType().equals(Car.Type.MITSUBISHI))
    .collect(Collectors.toList());

我认为你可以在接口外定义枚举,然后在接口中创建一个 Type getType() 方法,然后像这样使用它:

 cars.stream()
     .filter(c -> c.getType() == Type.MITSUBISHI)
     .collect(Collectors.toList());

(当然假设 Mitsubishi 实施将 return Type.MITSUBISHI Type getType())。