简介
“封装集合”(Encapsulate Collection)是一种重构手法,其核心目的是对类中的集合属性进行封装,以增强代码的安全性和可维护性。当直接暴露集合属性时,外部代码可以随意修改集合内容,这可能会破坏类的内部状态和业务逻辑。通过封装集合,可以控制对集合的访问和修改方式,只提供必要的操作接口。
针对的症状(代码坏味道)
- 集合属性直接暴露:类中的集合属性被声明为公共的,外部代码可以直接访问和修改该集合。
- 无法控制集合修改:外部代码可以自由地向集合中添加、删除元素,可能导致类的内部状态不一致。
- 代码耦合度高:外部代码依赖于集合的具体实现,当集合的实现发生变化时,需要修改大量的外部代码。
封装集合(Encapsulate Collection)的详细步骤
- 检查集合属性
- 找出类中直接暴露的集合属性,确认这些集合属性被外部代码直接访问和修改的情况。
- 将集合属性设为私有
- 把集合属性的访问修饰符改为
private
,防止外部代码直接访问该集合。
- 把集合属性的访问修饰符改为
- 提供访问方法
- 提供只读访问方法:创建一个方法来返回集合的副本,而不是直接返回集合本身,这样可以避免外部代码修改集合。
- 提供修改方法:根据业务需求,提供必要的方法来添加、删除集合中的元素,确保对集合的修改符合类的业务逻辑。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明封装集合的影响。
示例
假设有一个 Student
类,其中包含一个 List
类型的 courses
集合,该集合直接暴露给外部。
原始代码
import java.util.ArrayList;
import java.util.List;
public class Student {
public List<String> courses = new ArrayList<>();
}
重构步骤
- 检查集合属性:
courses
集合被声明为public
,外部代码可以直接访问和修改。 - 将集合属性设为私有:把
courses
的访问修饰符改为private
。 - 提供访问方法:
- 提供只读访问方法:创建
getCourses
方法,返回courses
的副本。 - 提供修改方法:创建
addCourse
和removeCourse
方法来控制对集合的修改。
- 提供只读访问方法:创建
重构后代码
import java.util.ArrayList;
import java.util.List;
public class Student {
private List<String> courses = new ArrayList<>();
public List<String> getCourses() {
return new ArrayList<>(courses);
}
public void addCourse(String course) {
courses.add(course);
}
public void removeCourse(String course) {
courses.remove(course);
}
}
练习
基础练习题
-
简单集合封装
-
给定以下 Java 代码,
Library
类中的books
集合直接暴露。请封装该集合。import java.util.ArrayList; import java.util.List; public class Library { public List<String> books = new ArrayList<>(); }
-
-
多类型集合封装
- 下面的 Java 代码中,
Inventory
类包含一个Map
类型的products
集合,该集合直接暴露。请封装该集合。
import java.util.HashMap; import java.util.Map; public class Inventory { public Map<String, Integer> products = new HashMap<>(); }
- 下面的 Java 代码中,
进阶练习题
-
集合封装与业务逻辑控制
-
在这段 Java 代码中,
Team
类的players
集合直接暴露。要求封装该集合,并在添加球员时,确保球队人数不超过 11 人。import java.util.ArrayList; import java.util.List; public class Team { public List<String> players = new ArrayList<>(); }
-
-
集合封装与返回值处理
- 给定以下 Java 代码,
Course
类的students
集合直接暴露。请封装该集合,并在获取学生列表时,返回按字母顺序排序后的副本。
import java.util.ArrayList; import java.util.List; public class Course { public List<String> students = new ArrayList<>(); }
- 给定以下 Java 代码,
综合拓展练习题
- 多集合封装与代码审查模拟
-
考虑一个简单的 Java 电商系统,有
Order
类,其中包含products
集合(List<Product>
)和discounts
集合(Map<String, Double>
),这两个集合都直接暴露。请对这些集合进行 “封装集合” 重构。 -
假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } } public class Order { public List<Product> products = new ArrayList<>(); public Map<String, Double> discounts = new HashMap<>(); }
-