You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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接口定义面积计算规范,各形状类实现接口,这部分符合开闭原则的扩展要求,但存在明显缺陷:

  1. 封装性缺失:Rectangle和Circle的成员变量是public的,外部可直接修改,破坏了封装原则。
  2. 客户端耦合过重:计算总面积依赖客户端先调用每个形状的CalcArea并收集结果,新增形状时需要修改客户端代码,不符合“对修改关闭”的要求。
  3. 代码冗余: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);
    }
}

方案优势

  1. 严格符合开闭原则:新增任何几何图形(如三角形、梯形),只需新增实现Shape接口的类,无需修改ShapeCalculator或现有代码。
  2. 良好的封装性:所有成员变量用private final修饰,通过构造器初始化,保证数据不可篡改。
  3. 低耦合:计算器类依赖抽象接口而非具体实现,降低模块间耦合度。
  4. 代码简洁高效:使用Stream API替代循环求和,可读性和执行效率更高。

内容的提问来源于stack exchange,提问作者Ali Hassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:47:33