
本文讲解如何通过添加公共方法(如复制构造器、除法运算等)让 weight 类自主管理内部状态,避免 project 类直接访问私有字段或方法,从而严格遵守面向对象的封装原则。
本文讲解如何通过添加公共方法(如复制构造器、除法运算等)让 weight 类自主管理内部状态,避免 project 类直接访问私有字段或方法,从而严格遵守面向对象的封装原则。
在面向对象编程中,封装的核心在于“隐藏实现细节,暴露安全接口”。你当前遇到的问题——Project 类无法访问 Weight 的私有成员 toOunces()、ounces 和 OUNCES_IN_A_POUND——并非缺陷,而是封装机制的正常体现。关键不在于绕过封装,而在于增强 Weight 类的公共契约,使其能独立完成所需计算。
✅ 正确做法:将逻辑内聚到 Weight 类中
Project 类不应自行进行单位换算或数学运算(如求和、平均、比较),而应通过 Weight 提供的语义化公共方法完成操作。这既保持了封装性,又提升了代码可读性与可维护性。
1. 添加复制构造器(Copy Constructor)
用于创建现有 Weight 实例的独立副本:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
public Weight(Weight other) {
if (other == null) throw new IllegalArgumentException("Weight cannot be null");
this.pounds = other.pounds;
this.ounces = other.ounces;
// normalize() is called implicitly in constructor, but safe to call again
this.normalize();
}
2. 添加 add() 方法(替代原 addTo(),更符合命名惯例)
public void add(Weight other) {
double totalOunces = this.toOunces() + other.toOunces();
this.pounds = (int) (totalOunces / OUNCES_IN_A_POUND);
this.ounces = totalOunces % OUNCES_IN_A_POUND;
this.normalize();
}
? 注意:原 addTo() 方法名易误解为“向参数对象添加”,实际是“向当前对象添加参数值”,故重命名为 add(Weight) 更准确、更符合 Java 惯例(如 StringBuilder.append())。
3. 添加 divideBy(double) 方法(支持求平均值)
public void divideBy(double divisor) {
if (divisor == 0) throw new ArithmeticException("Cannot divide by zero");
double totalOunces = this.toOunces();
double resultOunces = totalOunces / divisor;
this.pounds = (int) (resultOunces / OUNCES_IN_A_POUND);
this.ounces = resultOunces % OUNCES_IN_A_POUND;
this.normalize();
}
4. 补充必要的公共 getter(按需,非必须但推荐)
若后续需调试或扩展,可添加只读访问器(不破坏封装):
public double getOunces() { return this.toOunces(); } // 返回总盎司数(只读)
// 注意:不提供 setPounds/setOunces —— 状态变更应通过行为方法(如 add/divideBy)驱动
? 更新后的 Project 类(完全不触碰私有成员)
public class Project {
private static Weight findMinimum(Weight w1, Weight w2, Weight w3) {
Weight min = w1;
if (w2.lessThan(min)) min = w2;
if (w3.lessThan(min)) min = w3;
return min;
}
private static Weight findMaximum(Weight w1, Weight w2, Weight w3) {
Weight max = w1;
if (w2.lessThan(max) == false) max = w2; // 使用 lessThan 的逆逻辑
if (w3.lessThan(max) == false) max = w3;
return max;
}
private static Weight findAverage(Weight w1, Weight w2, Weight w3) {
Weight sum = new Weight(w1); // 复制 w1
sum.add(w2);
sum.add(w3);
sum.divideBy(3.0);
return sum;
}
public static void main(String[] args) {
Weight weight1 = new Weight(11, 3);
Weight weight2 = new Weight(7, 20);
Weight weight3 = new Weight(14, 6);
System.out.println("Weight 1: " + weight1);
System.out.println("Weight 2: " + weight2);
System.out.println("Weight 3: " + weight3);
System.out.println("Minimum: " + findMinimum(weight1, weight2, weight3));
System.out.println("Maximum: " + findMaximum(weight1, weight2, weight3));
System.out.println("Average: " + findAverage(weight1, weight2, weight3));
}
}
⚠️ 关键注意事项
- 绝不暴露私有字段:ounces、pounds、OUNCES_IN_A_POUND 必须保持 private;外部类永远不直接读写。
- 方法职责单一:add() 负责累加,divideBy() 负责缩放,lessThan() 负责比较——每个方法只做一件事,且由 Weight 自主完成全部内部计算。
- 不变性优先:当前设计为“可变对象”(修改自身状态)。若追求函数式风格,可改为返回新 Weight 实例(如 public Weight addedTo(Weight other)),但需权衡性能与语义清晰度。
- 异常防御:对 null 输入、除零等边界情况主动校验,提升健壮性。
通过以上重构,Weight 不再只是一个数据容器,而成为一个具备完整行为能力的领域对象。Project 类仅作为协调者调用其语义明确的方法,真正实现了“高内聚、低耦合”的封装目标——这正是面向对象设计的精髓所在。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










