Java开闭原则实践:两种几何图形总面积计算方案优劣咨询
基于开闭原则的几何图形面积计算方案对比分析
我正在进行一项基于Java的SOLID原则练习,核心聚焦于开闭原则。练习要求编写程序计算不同几何图形的总面积,我设计了两种实现方案,现咨询哪种方案更符合开闭原则,或者是否存在更优的实现方式。
第一种方案
abstract class Shape { public abstract double CalcArea(); } class Circle extends Shape { private double radius; public Circle(double radius) { this.radius = radius; } public double getRadius() { return radius; } @Override public double CalcArea(){ return Math.PI * Math.pow(radius, 2); } } class Rectangle extends Shape { private double width; private double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } public double getWidth() { return width; } public double getHeight() { return height; } @Override public double CalcArea(){ return width*height; } } public class ShapeCalculator { public double calculateTotalArea(List<Shape> shapes) { double totalArea = 0; for (Shape shape : shapes) { if (shape instanceof Circle) { Circle circle = (Circle) shape; totalArea += circle.CalcArea(); } else if (shape instanceof Rectangle) { Rectangle rectangle = (Rectangle) shape; totalArea += rectangle.CalcArea(); } // Add more conditions for other shapes (e.g., Triangle) } return totalArea; } } public static void main (String[] args) { Rectangle abcd = new Rectangle(5.5 , 8); Circle circle1 = new Circle(4); List<Shape> geoshape = new ArrayList(); geoshape.add(abcd); geoshape.add(circle1); ShapeCalculator calculate = new ShapeCalculator(); calculate.calculateTotalArea(geoshape); }
方案分析
这个方案的核心问题出在ShapeCalculator类的实现上:它通过instanceof判断具体形状类型,再调用对应方法。如果要新增几何图形(比如三角形),必须修改calculateTotalArea方法,添加新的else if分支,直接违反了开闭原则(对扩展开放,对修改关闭)。虽然抽象类Shape的设计思路正确,但计算器类的逻辑把扩展成本转移到了修改原有代码上。
第二种方案
public interface Shapes { public abstract double CalcArea(); } public class Rectangle implements Shapes { public double length , width; public Rectangle(double width , double length){ this.length = length; this.width = width; } @Override public double CalcArea(){ return width*length; } } public class Circle implements Shapes { double radius; public Circle(double radius){ this.radius = radius; } @Override public double CalcArea(){ return radius*radius*3.14; } } public class CalculateTotalArea { public double CalculateTotalArea(ArrayList<Double> Areas){ double totalArea = 0; for (Double area : Areas){ totalArea += area; } return totalArea; } } public static void main(String[] args) { Rectangle rectangle1 = new Rectangle(8 , 2); Circle circle1 = new Circle(7); ArrayList<Double> AreaList = new ArrayList(); AreaList.add(rectangle1.CalcArea()); AreaList.add(circle1.CalcArea()); CalculateTotalArea result = new CalculateTotalArea(); System.out.println("The area of the Circle : "+circle1.CalcArea()); System.out.println("The area of the rectangle : "+rectangle1.CalcArea()); System.out.println("The Total Area is : "+result.CalculateTotalArea(AreaList)); }
方案分析
这个方案用Shapes接口定义面积计算规范,各形状类实现接口,这部分符合开闭原则的扩展要求,但存在明显缺陷:
- 封装性缺失:
Rectangle和Circle的成员变量是public的,外部可直接修改,破坏了封装原则。 - 客户端耦合过重:计算总面积依赖客户端先调用每个形状的
CalcArea并收集结果,新增形状时需要修改客户端代码,不符合“对修改关闭”的要求。 - 代码冗余:
CalculateTotalArea类仅做简单求和,功能单一且没必要单独封装,逻辑可以更紧凑。
更优的实现方案
结合两种方案的优点,同时严格遵循开闭原则,最优实现如下:
// 定义形状接口,采用Java小驼峰命名规范 public interface Shape { double calcArea(); } // 圆形实现类,封装成员变量 public class Circle implements Shape { private final double radius; public Circle(double radius) { this.radius = radius; } @Override public double calcArea() { return Math.PI * Math.pow(radius, 2); } } // 矩形实现类,封装成员变量 public class Rectangle implements Shape { private final double width; private final double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public double calcArea() { return width * height; } } // 总面积计算器,依赖Shape接口,无需关心具体实现 public class ShapeCalculator { public double calculateTotalArea(List<Shape> shapes) { // 使用Stream API简化求和逻辑 return shapes.stream() .mapToDouble(Shape::calcArea) .sum(); } } // 测试主类 public class ShapeApplication { public static void main(String[] args) { Shape rectangle = new Rectangle(5.5, 8); Shape circle = new Circle(4); // 使用不可变列表提高安全性 List<Shape> shapes = List.of(rectangle, circle); ShapeCalculator calculator = new ShapeCalculator(); double totalArea = calculator.calculateTotalArea(shapes); System.out.println("几何图形总面积:" + totalArea); } }
方案优势
- 严格符合开闭原则:新增任何几何图形(如三角形、梯形),只需新增实现
Shape接口的类,无需修改ShapeCalculator或现有代码。 - 良好的封装性:所有成员变量用
private final修饰,通过构造器初始化,保证数据不可篡改。 - 低耦合:计算器类依赖抽象接口而非具体实现,降低模块间耦合度。
- 代码简洁高效:使用Stream API替代循环求和,可读性和执行效率更高。
内容的提问来源于stack exchange,提问作者Ali Hassan
相关产品推荐
相关产品推荐

