Java多态实战如何用Shape接口计算三角形、矩形和圆的周长附完整代码在面向对象编程的世界里多态性就像一把瑞士军刀它能让你用统一的接口处理不同类型的对象。想象一下你正在开发一个图形处理系统需要计算各种形状的周长。如果没有多态你可能需要写一堆if-else语句来判断图形类型而有了多态代码会变得优雅而富有扩展性。让我们从一个实际案例出发设计一个能够计算三角形、矩形和圆周长的系统。这个案例完美展示了多态如何简化代码结构提高可维护性。我们将使用Java的接口特性来实现这一目标同时确保代码足够健壮能够处理各种边界情况。1. 设计Shape接口与实现类1.1 定义Shape接口多态的核心在于定义一个统一的接口。对于图形计算系统我们首先创建一个Shape接口public interface Shape { double calculatePerimeter(); }这个简单的接口声明了一个calculatePerimeter()方法我们使用更具语义化的方法名而不是简单的length()所有实现该接口的类都必须提供这个方法的具体实现。1.2 实现具体图形类三角形类实现public class Triangle implements Shape { private final double sideA; private final double sideB; private final double sideC; public Triangle(double a, double b, double c) { if (!isValidTriangle(a, b, c)) { throw new IllegalArgumentException(Invalid triangle sides); } this.sideA a; this.sideB b; this.sideC c; } private boolean isValidTriangle(double a, double b, double c) { return a 0 b 0 c 0 a b c a c b b c a; } Override public double calculatePerimeter() { return sideA sideB sideC; } }矩形类实现public class Rectangle implements Shape { private final double length; private final double width; public Rectangle(double length, double width) { if (length 0 || width 0) { throw new IllegalArgumentException(Length and width must be positive); } this.length length; this.width width; } Override public double calculatePerimeter() { return 2 * (length width); } }圆形类实现public class Circle implements Shape { private static final double PI 3.141592653589793; private final double radius; public Circle(double radius) { if (radius 0) { throw new IllegalArgumentException(Radius must be positive); } this.radius radius; } Override public double calculatePerimeter() { return 2 * PI * radius; } }每个类都实现了Shape接口但提供了不同的calculatePerimeter()实现这就是多态的魅力所在。2. 构建健壮的输入处理系统2.1 输入验证与图形创建我们需要一个能够根据用户输入创建相应图形对象的工厂类public class ShapeFactory { public static Shape createShape(double... dimensions) { if (dimensions null || dimensions.length 0 || dimensions.length 3) { throw new IllegalArgumentException(Invalid number of dimensions); } try { switch (dimensions.length) { case 1: return new Circle(dimensions[0]); case 2: return new Rectangle(dimensions[0], dimensions[1]); case 3: return new Triangle(dimensions[0], dimensions[1], dimensions[2]); default: throw new AssertionError(Unexpected number of dimensions); } } catch (IllegalArgumentException e) { return new NullShape(); // 处理无效输入 } } private static class NullShape implements Shape { Override public double calculatePerimeter() { return 0; } } }2.2 处理用户输入下面是处理用户输入的主类实现import java.util.Scanner; public class ShapeCalculator { public static void main(String[] args) { Scanner scanner new Scanner(System.in); System.out.println(Enter dimensions for shapes (1 for circle, 2 for rectangle, 3 for triangle):); while (scanner.hasNextLine()) { String line scanner.nextLine().trim(); if (line.isEmpty()) continue; String[] parts line.split(\\s); double[] dimensions new double[parts.length]; try { for (int i 0; i parts.length; i) { dimensions[i] Double.parseDouble(parts[i]); } Shape shape ShapeFactory.createShape(dimensions); System.out.printf(Perimeter: %.2f%n, shape.calculatePerimeter()); } catch (NumberFormatException e) { System.out.println(Invalid input: please enter numbers only); } catch (IllegalArgumentException e) { System.out.println(Error: e.getMessage()); } } scanner.close(); } }3. 多态的高级应用技巧3.1 使用策略模式增强灵活性我们可以进一步扩展系统使其能够计算其他图形的周长而无需修改现有代码public class Pentagon implements Shape { private final double side; public Pentagon(double side) { if (side 0) { throw new IllegalArgumentException(Side length must be positive); } this.side side; } Override public double calculatePerimeter() { return 5 * side; } }只需在ShapeFactory中添加相应的case系统就能支持五边形计算这体现了开闭原则对扩展开放对修改关闭。3.2 使用集合处理多个图形多态真正发挥威力是在处理图形集合时ListShape shapes Arrays.asList( new Circle(5), new Rectangle(3, 4), new Triangle(3, 4, 5) ); double totalPerimeter shapes.stream() .mapToDouble(Shape::calculatePerimeter) .sum(); System.out.printf(Total perimeter of all shapes: %.2f%n, totalPerimeter);这段代码展示了多态的强大之处——我们可以用统一的方式处理不同类型的对象。4. 测试与异常处理4.1 单元测试示例良好的测试是健壮代码的保障。以下是使用JUnit的测试示例import org.junit.Test; import static org.junit.Assert.*; public class ShapeTest { private static final double DELTA 0.0001; Test public void testCirclePerimeter() { Shape circle new Circle(1); assertEquals(2 * Math.PI, circle.calculatePerimeter(), DELTA); } Test public void testRectanglePerimeter() { Shape rectangle new Rectangle(3, 4); assertEquals(14, rectangle.calculatePerimeter(), DELTA); } Test public void testTrianglePerimeter() { Shape triangle new Triangle(3, 4, 5); assertEquals(12, triangle.calculatePerimeter(), DELTA); } Test(expected IllegalArgumentException.class) public void testInvalidTriangle() { new Triangle(1, 1, 3); } }4.2 性能优化考虑对于高性能场景我们可以做一些优化使用final类和方怯避免虚方法调用开销对于简单图形考虑值对象模式缓存常用计算结果如圆周率倍数public final class OptimizedCircle implements Shape { private static final double TWO_PI 2 * Math.PI; private final double radius; public OptimizedCircle(double radius) { this.radius radius; } Override public double calculatePerimeter() { return TWO_PI * radius; } }5. 实际项目中的应用建议在实际项目中应用这种多态设计时有几个经验值得分享文档很重要为每个图形类添加清晰的JavaDoc说明参数单位和边界条件考虑国际化周长计算可能因单位系统而异米 vs 英尺日志记录在工厂方法中添加适当的日志便于调试防御性编程验证所有输入参数避免后续计算错误/** * Represents a geometric shape that can calculate its perimeter. */ public interface Shape { /** * Calculates the perimeter of the shape. * return the perimeter in meters * throws IllegalStateException if the shape is in invalid state */ double calculatePerimeter() throws IllegalStateException; }在团队协作中确保所有实现类都遵循相同的约定和规范这样多态才能真正发挥其价值。