Smell Detail

Divergent Change

发散式变化

Change Preventers

A class needs to be modified frequently for different, unrelated reasons.

Define

Introduction

When a class needs to be modified for many different reasons, you've encountered Divergent Change. This violates the Single Responsibility Principle (SRP) and indicates the class is doing too much.

Key Identifiers

  • The class must change for different reasons
  • Modifying one feature requires editing multiple parts of the same class
  • The class's responsibilities are unclear
  • Violates the Single Responsibility Principle

Refactoring Suggestions

  1. Extract Class: Separate distinct responsibilities into their own classes
  2. Single Responsibility: Ensure each class has only one reason to change
  3. Delegate / Composition: Use composition to replace a large, monolithic class
  4. Modular Design: Organize code by functional or domain boundaries

Explanation

This class changes for different reasons: payroll rules, tax regulations, reporting formats, database schema, etc. Responsibilities should be split so each class handles only one axis of change.

Code Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class Employee {
private String name;
private double salary;
private String department;
private String address;
private String email;
// Needs to be modified due to payroll policy changes
public double calculatePay() {
if ("Engineering".equals(department)) {
return salary * 1.2;
} else if ("Sales".equals(department)) {
return salary * 1.1;
} else if ("Management".equals(department)) {
return salary * 1.5;
}
return salary;
}
// Needs to be modified due to tax law changes
public double calculateTax() {
double pay = calculatePay();
if (pay > 100000) {
return pay * 0.35;
} else if (pay > 50000) {
return pay * 0.25;
}
return pay * 0.15;
}
// Needs to be modified due to report format changes
public String generateReport() {
return "Employee: " + name +
"\nDepartment: " + department +
"\nPay: " + String.valueOf(calculatePay()) +
"\nTax: " + String.valueOf(calculateTax());
}
// Needs to be modified due to database structure changes
public void saveToDatabase() {
// Database save logic
System.out.println("Saving to database...");
}
// Needs to be modified due to email system changes
public void sendPayslip() {
System.out.println("Sending payslip to: " + this.email);
}
// Getters and setters - may change due to data format requirements
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
}