假设我有以下简单的例子:
// This is provided to me from another jar so cannot be changed.
public interface Shape {
double calculateArea();
double calculatePerimeter();
}
public class Triangle implements Shape {
private double side1;
private double side2;
private double side3;
public Triangle(double side1, double side2, double side3) {
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
}
@Override
public double calculateArea() {
// Heron's formula to calculate area of a triangle
double s = (side1 + side2 + side3) / 2;
return Math.sqrt(s * (s - side1) * (s - side2) * (s - side3));
}
@Override
public double calculatePerimeter() {
return side1 + side2 + side3;
}
}
public class Square implements Shape {
private double side;
public Square(double side) {
this.side = side;
}
@Override
public double calculateArea() {
return side * side;
}
@Override
public double calculatePerimeter() {
return 4 * side;
}
public void squareSpecificMethod(){
// Does something specific for squares only
}
}
public class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public double calculatePerimeter() {
return 2 * Math.PI * radius;
}
}
public class Main {
public static void main(String[] args) {
// Example usage
Shape triangle = new Triangle(3, 4, 5);
System.out.println("Triangle Area: " + triangle.calculateArea());
System.out.println("Triangle Perimeter: " + triangle.calculatePerimeter());
Shape square = new Square(5);
System.out.println("Square Area: " + square.calculateArea());
System.out.println("Square Perimeter: " + square.calculatePerimeter());
Shape circle = new Circle(3);
System.out.println("Circle Area: " + circle.calculateArea());
System.out.println("Circle Perimeter: " + circle.calculatePerimeter());
}
}
如果我想访问方法 squareSpecificMethod()
我可以执行以下操作,但可能必须在多个地方多次执行此操作:
((Square) square).squareSpecificMethod();
或者同样必须在多个地方执行此操作
if (square instanceof Square) {
((Square) square).squareSpecificMethod();
}
或者将其更改为(但后来我认为为了多态性我应该引用基本接口):
Square square = new Square(5);
或者使用访问者模式,但我无法更改形状界面。
我怎样才能避免强制转换或使用instanceOf,因为从我读到的内容来看,这可能是潜在的代码味道?
当我可能需要调用特定于实现的方法但可能直到运行时才知道实现时,我正在努力寻找在运行时获取具体类的最佳方法。
如果我向其他实现添加特定方法,我也会遇到同样的问题。 而且在多个地方检查instanceof或cast似乎很麻烦
仅限于 Java 11
正如 QBrute 在评论中指出的那样,如果您可以使用 JDK-14 及更高版本,模式匹配可能会简化在构造中调用特定于实现的方法,如下所示:
void invokeShapeMethod(Shape shape) {
System.out.println(shape.getClass().getSimpleName() + " Area: " + shape.calculateArea());
System.out.println(shape.getClass().getSimpleName() + " Perimeter: " + shape.calculatePerimeter());
switch (shape) {
case Square s -> s.squareSpecificMethod();
default -> {
}
}
}
这会跨接口实现调用默认方法,同时切换形状类型以调用其特定方法。