重构目标:将系统的核心操作抽象为接口,从而解耦业务逻辑与具体实现。后续可以轻松替换存储方式(如从内存换成数据库)或增加新功能
- 定义核心接口
```java
// 学生实体类
public class Student {
private String id;
private String name;
private int age;
// 构造方法、getter/setter 省略
}
// 学生管理接口 - 定义所有对外提供的操作
public interface StudentService {
boolean addStudent(Student student);
boolean deleteStudent(String id);
boolean updateStudent(Student student);
Student findStudentById(String id);
List<Student> findAllStudents();
}
```
- 基于内存的实现(原有系统可能长这样)
```java
// 原来的实现:直接使用 ArrayList,业务代码与具体存储耦合
public class MemoryStudentManager {
private List<Student> students = new ArrayList<>();
public boolean addStudent(Student s) { ... }
public Student findStudentById(String id) { ... }
// ...
}
```
- 重构:让实现类实现接口
```java
// 重构后:实现 StudentService 接口
public class MemoryStudentService implements StudentService {
private List<Student> students = new ArrayList<>();
@Override
public boolean addStudent(Student student) {
if (findStudentById(student.getId()) != null) {
return false; // 已存在
}
return students.add(student);
}
@Override
public boolean deleteStudent(String id) {
return students.removeIf(s -> s.getId().equals(id));
}
@Override
public boolean updateStudent(Student student) {
Student old = findStudentById(student.getId());
if (old == null) return false;
old.setName(student.getName());
old.setAge(student.getAge());
return true;
}
@Override
public Student findStudentById(String id) {
return students.stream()
.filter(s -> s.getId().equals(id))
.findFirst()
.orElse(null);
}
@Override
public List<Student> findAllStudents() {
return new ArrayList<>(students);
}
}
```
- 使用接口编程(客户端代码)
```java
public class StudentManagementSystem {
private StudentService studentService;
// 通过构造方法注入具体的实现(依赖注入)
public StudentManagementSystem(StudentService studentService) {
this.studentService = studentService;
}
public void showAllStudents() {
studentService.findAllStudents().forEach(System.out::println);
}
// 其他业务方法...
}
// 主程序
public class Main {
public static void main(String[] args) {
// 只需替换这一行,就可以切换存储方式
StudentService service = new MemoryStudentService();
// StudentService service = new DatabaseStudentService(); // 未来扩展
StudentManagementSystem system = new StudentManagementSystem(service);
system.addStudent(new Student("1", "张三", 20));
system.showAllStudents();
}
}
```
- 重构带来的好处
方面 重构前(具体类) 重构后(接口)
扩展性 要换存储方式必须修改大量代码 新增 DatabaseStudentService 即可,符合开闭原则
测试性 单元测试必须依赖真实的列表 可以传入 Mock 实现,便于隔离测试
可维护性 业务逻辑与存储细节混杂 接口清晰定义了契约,实现者各司其职
多态性 不支持多种管理策略 可以用同一个 StudentManagementSystem 配合不同实现
- 接口定义中的进阶设计(可选)
你还可以在接口中添加默认方法或静态方法,提供公共逻辑:
```java
public interface StudentService {
// 核心抽象方法 ...
// 默认方法:检查学生是否成年
default boolean isAdult(Student student) {
return student.getAge() >= 18;
}
// 静态方法:创建默认的内存实现
static StudentService newMemoryInstance() {
return new MemoryStudentService();
}
}
```
使用时:StudentService service = StudentService.newMemoryInstance();
总结
通过接口的定义,将学生管理系统的操作契约与具体实现分离。这是面向对象设计中的面向接口编程原则,也是 Spring 等框架的核心思想。重构后的系统可以轻松应对需求变化(如从内存存储改为数据库存储),同时极大提升了代码的可测试性和可维护性。