重构手法——数据重组类 | 数据完整性操作 | 封装变量

50 阅读4分钟

简介

“封装变量”(Encapsulate Variable)是一种重要的重构手法,主要用于提高代码的安全性和可维护性。当变量直接暴露时,外部代码可以随意访问和修改它,这可能会破坏对象的内部状态,导致难以调试和维护的问题。通过封装变量,我们可以隐藏变量的直接访问,提供受控的访问接口,从而更好地控制变量的使用。

针对的症状(代码坏味道)

  • 变量直接暴露:类中的变量被声明为公共(public),外部代码可以直接访问和修改这些变量,破坏了数据的封装性。
  • 缺乏数据验证:直接访问变量使得外部代码可以随意赋值,没有对变量的赋值进行有效性检查,可能导致对象处于不一致的状态。
  • 代码耦合度高:外部代码依赖于变量的具体实现,当变量的类型或用途发生变化时,需要修改大量的外部代码。

封装变量(Encapsulate Variable)的详细步骤

  1. 将变量设为私有
    • 把需要封装的变量的访问修饰符从 publicprotected 改为 private,防止外部代码直接访问该变量。
  2. 提供访问方法
    • 创建 getter 方法:为变量创建一个公共的 getter 方法,用于获取变量的值。方法名通常遵循 getVariableName 的命名规则(如果是布尔类型的变量,通常使用 isVariableName)。
    • 创建 setter 方法(可选):如果需要允许外部代码修改变量的值,为变量创建一个公共的 setter 方法。在 setter 方法中,可以添加数据验证逻辑,确保赋给变量的值是合法的。
  3. 替换直接访问
    • 将所有直接访问该变量的代码替换为调用相应的 gettersetter 方法。
  4. 测试
    • 编译代码:确保代码编译通过,没有任何语法错误。
    • 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
    • 手动测试:如果有必要,进行手动测试以验证功能的正确性。
  5. 代码审查
    • 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
    • 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明封装变量的影响。

示例

假设有一个 Person 类,其中的 age 变量直接暴露。

原始代码

public class Person {
    public int age;
}

重构步骤

  1. 将变量设为私有:把 age 变量的访问修饰符改为 private
  2. 提供访问方法:创建 getAgesetAge 方法,并在 setAge 方法中添加数据验证逻辑。
  3. 替换直接访问:将所有直接访问 age 变量的代码替换为调用 getAgesetAge 方法。

重构后代码

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.");
        }
    }
}

练习

基础练习题

  1. 简单变量封装

    • 给定以下 Java 代码,Product 类中的 price 变量直接暴露。请封装该变量。

        public class Product {
          public double price;
      }
      
  2. 布尔类型变量封装

    • 下面的 Java 代码中,User 类的 isVerified 变量直接暴露。请封装该变量。
    public class User {
        public boolean isVerified;
    }
    

进阶练习题

  1. 变量封装与复杂验证逻辑

    • 在这段 Java 代码中,Employee 类的 salary 变量直接暴露。要求封装该变量,并在设置 salary 时,确保其值不低于当地最低工资标准(假设最低工资标准为 2000)。
    public class Employee {
        public double salary;
    }
    
  2. 变量封装与业务逻辑关联

    • 给定以下 Java 代码,Account 类的 balance 变量直接暴露。请封装该变量,并在取款时(调用 withdraw 方法),确保余额足够。
    public class Account {
        public double balance;
    
        public void withdraw(double amount) {
            balance -= amount;
        }
    }
    

综合拓展练习题

  1. 多变量封装与代码审查模拟

    • 考虑一个简单的 Java 学生管理系统,有 Student 类,其中包含 nameagegrade 变量,这些变量都直接暴露。请对这些变量进行 “封装变量” 重构。
    • 假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
    public class Student {
        public String name;
        public int age;
        public double grade;
    }