简介
“封装变量”(Encapsulate Variable)是一种重要的重构手法,主要用于提高代码的安全性和可维护性。当变量直接暴露时,外部代码可以随意访问和修改它,这可能会破坏对象的内部状态,导致难以调试和维护的问题。通过封装变量,我们可以隐藏变量的直接访问,提供受控的访问接口,从而更好地控制变量的使用。
针对的症状(代码坏味道)
- 变量直接暴露:类中的变量被声明为公共(
public),外部代码可以直接访问和修改这些变量,破坏了数据的封装性。 - 缺乏数据验证:直接访问变量使得外部代码可以随意赋值,没有对变量的赋值进行有效性检查,可能导致对象处于不一致的状态。
- 代码耦合度高:外部代码依赖于变量的具体实现,当变量的类型或用途发生变化时,需要修改大量的外部代码。
封装变量(Encapsulate Variable)的详细步骤
- 将变量设为私有
- 把需要封装的变量的访问修饰符从
public或protected改为private,防止外部代码直接访问该变量。
- 把需要封装的变量的访问修饰符从
- 提供访问方法
- 创建
getter方法:为变量创建一个公共的getter方法,用于获取变量的值。方法名通常遵循getVariableName的命名规则(如果是布尔类型的变量,通常使用isVariableName)。 - 创建
setter方法(可选):如果需要允许外部代码修改变量的值,为变量创建一个公共的setter方法。在setter方法中,可以添加数据验证逻辑,确保赋给变量的值是合法的。
- 创建
- 替换直接访问
- 将所有直接访问该变量的代码替换为调用相应的
getter和setter方法。
- 将所有直接访问该变量的代码替换为调用相应的
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明封装变量的影响。
示例
假设有一个 Person 类,其中的 age 变量直接暴露。
原始代码
public class Person {
public int age;
}
重构步骤
- 将变量设为私有:把
age变量的访问修饰符改为private。 - 提供访问方法:创建
getAge和setAge方法,并在setAge方法中添加数据验证逻辑。 - 替换直接访问:将所有直接访问
age变量的代码替换为调用getAge和setAge方法。
重构后代码
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
throw new IllegalArgumentException("Age cannot be negative.");
}
}
}
练习
基础练习题
-
简单变量封装
-
给定以下 Java 代码,
Product类中的price变量直接暴露。请封装该变量。public class Product { public double price; }
-
-
布尔类型变量封装
- 下面的 Java 代码中,
User类的isVerified变量直接暴露。请封装该变量。
public class User { public boolean isVerified; } - 下面的 Java 代码中,
进阶练习题
-
变量封装与复杂验证逻辑
- 在这段 Java 代码中,
Employee类的salary变量直接暴露。要求封装该变量,并在设置salary时,确保其值不低于当地最低工资标准(假设最低工资标准为 2000)。
public class Employee { public double salary; } - 在这段 Java 代码中,
-
变量封装与业务逻辑关联
- 给定以下 Java 代码,
Account类的balance变量直接暴露。请封装该变量,并在取款时(调用withdraw方法),确保余额足够。
public class Account { public double balance; public void withdraw(double amount) { balance -= amount; } } - 给定以下 Java 代码,
综合拓展练习题
-
多变量封装与代码审查模拟
- 考虑一个简单的 Java 学生管理系统,有
Student类,其中包含name、age和grade变量,这些变量都直接暴露。请对这些变量进行 “封装变量” 重构。 - 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
public class Student { public String name; public int age; public double grade; } - 考虑一个简单的 Java 学生管理系统,有