面向对象

1

2 SOLID 原则

2.1 开闭原则 OCP

定义:软件实体(类、模块、函数)应当对扩展开放,对修改关闭。

简单理解:不要修改已有代码,而是增加代码来扩展行为。

2.2 单一职责原则 SRP

定义:一个类只有一个引起他变化的原因。

简单理解:一个类或者模块应该仅做一件事,并且将这件事情做好。

典型代码实例如下:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// 职责1: 只负责生成报告核心内容
public class ReportGenerator {
private String data;

public ReportGenerator(String data) {
this.data = data;
}

public String generate() {
// ... 核心生成逻辑 ...
return reportContent;
}
}

// 职责2: 只负责报告格式转换
public interface ReportFormatter {
String format(String content);
}

public class HtmlFormatter implements ReportFormatter {
@Override
public String format(String content) {
// ... HTML格式化逻辑 ...
return formattedContent;
}
}

public class PdfFormatter implements ReportFormatter {
@Override
public String format(String content) {
// ... PDF格式化逻辑 (可能调用外部库) ...
return formattedContent;
}
}

// 职责3: 只负责报告持久化
public interface ReportRepository {
void save(String content, String filename);
}

public class FileSystemRepository implements ReportRepository {
@Override
public void save(String content, String filename) {
// ... 文件I/O操作 ...
}
}

// 职责4: 只负责报告发送
public interface ReportSender {
void send(String content, String recipient);
}

public class EmailReportSender implements ReportSender {
@Override
public void send(String content, String recipient) {
// ... 邮件发送逻辑 ...
}
}

// 高层模块/客户端代码 (组合各个职责)
public class ReportService {
private ReportGenerator generator;
private ReportFormatter formatter;
private ReportRepository repository;
private ReportSender sender;

// 通过构造器或Setter注入依赖
public ReportService(ReportGenerator generator, ReportFormatter formatter,
ReportRepository repository, ReportSender sender) {
this.generator = generator;
this.formatter = formatter;
this.repository = repository;
this.sender = sender;
}

public void createAndSendReport(String filename, String recipient, String formatType) {
// 1. 生成内容
String content = generator.generate();

// 2. 格式化 (根据formatType选择Formatter, 这里简化)
String formattedContent = formatter.format(content);

// 3. 保存
repository.save(formattedContent, filename);

// 4. 发送
sender.send(formattedContent, recipient);
}
}

2.3 依赖倒置原则 DIP

定义:

  1. 高层模块不应该依赖于低层模块,两者都应该依赖于抽象。
  2. 抽象不应该依赖于细节,细节应该依赖于抽象。
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
61
62
63
64
65
66
67
// 步骤1: 定义抽象接口 (高层和低层都将依赖它)
public interface DataRepository {
void save(String data);
}

// 步骤2: 低层模块 - 具体实现1: MySQL
public class MySQLDatabase implements DataRepository {
@Override
public void save(String data) {
// ... 具体的 MySQL 保存逻辑 ...
System.out.println("Saving data to MySQL: " + data);
}
}

// 步骤2: 低层模块 - 具体实现2: PostgreSQL (新增实现很容易)
public class PostgreSQLDatabase implements DataRepository {
@Override
public void save(String data) {
// ... 具体的 PostgreSQL 保存逻辑 ...
System.out.println("Saving data to PostgreSQL: " + data);
}
}

// 步骤2: 低层模块 - 具体实现3: 文件系统 (新增实现很容易)
public class FileSystemRepository implements DataRepository {
@Override
public void save(String data) {
// ... 具体的文件保存逻辑 ...
System.out.println("Saving data to file: " + data);
}
}

// 步骤3: 修改高层模块 - 只依赖抽象接口 DataRepository
public class ReportService {
private DataRepository repository; // 依赖抽象!

// 步骤5: 依赖注入 (通过构造函数)
public ReportService(DataRepository repository) {
this.repository = repository; // 接收注入的具体实现
}

public void generateReport(String reportData) {
// ... 生成报告的复杂业务逻辑 (核心策略) 不变 ...
repository.save(reportData); // 通过接口调用
}
}

// 客户端使用 (负责组装对象,决定具体实现)
public class Client {
public static void main(String[] args) {
// 选择并创建具体的低层实现
DataRepository mySqlRepo = new MySQLDatabase();
// DataRepository pgRepo = new PostgreSQLDatabase();
// DataRepository fsRepo = new FileSystemRepository();

// 将依赖注入高层模块
ReportService reportService = new ReportService(mySqlRepo); // 注入 MySQL
// ReportService reportService = new ReportService(pgRepo); // 注入 PostgreSQL
// ReportService reportService = new ReportService(fsRepo); // 注入文件系统

reportService.generateReport("Important Report Data");
// 输出取决于注入的具体实现:
// 注入 MySQL: Saving data to MySQL: Important Report Data
// 注入 PostgreSQL: Saving data to PostgreSQL: Important Report Data
// 注入 FileSystem: Saving data to file: Important Report Data
}
}

2.4 里氏替换原则

定义:子类型必须能够替换掉他们的父类型,程序的行为仍保持正确。

通俗理解:子类不能违背父类的语义和契约。

2.5 接口隔离原则

定义:客户端不应该被迫依赖它不使用的方法。

通俗理解:一个接口只包含调用者真正需要的方法。