0%

六大原则

面向对象设计的六大原则

面向对象设计(OOD)的六大原则是软件设计的基石,旨在提高代码的可维护性、可扩展性和复用性。这些原则相互关联,共同指导开发者构建灵活、健壮的系统。

开闭原则(Open-Closed Principle, OCP)

核心思想

对扩展开放,对修改关闭
即软件实体(类、模块、接口等)应允许通过扩展新增功能,而无需修改原有代码。

实现方式

  • 通过抽象基类接口定义稳定的核心逻辑,具体实现延迟到子类。
  • 新增功能时,只需添加新的子类或实现类,而非修改现有代码。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 抽象图形接口(稳定)
interface Shape {
double area();
}

// 现有实现(无需修改)
class Circle implements Shape {
private double radius;
@Override
public double area() { return Math.PI * radius * radius; }
}

// 扩展新功能(新增类,不修改原有代码)
class Rectangle implements Shape {
private double width, height;
@Override
public double area() { return width * height; }
}

优势

  • 减少修改原有代码带来的风险(如引入新 bug)。
  • 提高系统的适应性和可扩展性。

里氏代换原则(Liskov Substitution Principle, LSP)

核心思想

子类可以替换父类出现的任何地方,且替换后不会改变原有程序的正确性
即子类必须完全遵守父类的行为契约,不能破坏父类的功能逻辑。

违反场景

  • 子类重写父类方法时,改变了方法的预期行为(如返回值范围、异常抛出)。
  • 子类新增父类未声明的约束(如参数校验更严格)。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 父类:矩形
class Rectangle {
protected int width, height;
public void setWidth(int w) { width = w; }
public void setHeight(int h) { height = h; }
public int area() { return width * height; }
}

// 子类:正方形(符合里氏代换)
class Square extends Rectangle {
@Override
public void setWidth(int w) {
super.setWidth(w);
super.setHeight(w); // 保持宽高相等,不破坏父类逻辑
}
@Override
public void setHeight(int h) {
super.setWidth(h);
super.setHeight(h);
}
}

优势

  • 保证继承关系的合理性,避免因子类替换导致的逻辑错误。
  • 增强代码的可替换性,便于测试和扩展。

依赖倒转原则(Dependency Inversion Principle, DIP)

核心思想

依赖于抽象,而非具体实现
即高层模块不应依赖低层模块,两者都应依赖抽象;抽象不应依赖细节,细节应依赖抽象。

实现方式

  • 通过接口抽象类定义交互契约,高层模块调用抽象接口。
  • 低层模块实现抽象接口,使高层模块与具体实现解耦。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 抽象接口(高层与低层共同依赖)
interface MessageSender {
void send(String message);
}

// 低层实现(依赖抽象)
class EmailSender implements MessageSender {
@Override
public void send(String message) { /* 发送邮件 */ }
}

// 高层模块(依赖抽象,不依赖具体实现)
class NotificationService {
private MessageSender sender;
// 构造注入抽象接口
public NotificationService(MessageSender sender) {
this.sender = sender;
}
public void notify(String message) {
sender.send(message); // 调用抽象方法
}
}

优势

  • 降低模块间的耦合度,便于替换低层实现(如从邮件发送改为短信发送)。
  • 提高系统的灵活性和可维护性。

接口隔离原则(Interface Segregation Principle, ISP)

核心思想

使用多个专用接口,而非一个通用接口
即接口应最小化,每个接口只包含客户端所需的方法,避免客户端依赖不需要的方法。

违反场景

  • 一个接口包含过多方法,导致实现类被迫实现无关方法。
  • 客户端依赖于其不使用的方法,增加耦合度。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 错误:通用接口包含过多方法
interface Worker {
void work();
void eat();
void sleep();
}

// 正确:拆分多个专用接口
interface Workable { void work(); }
interface Eatable { void eat(); }
interface Sleepable { void sleep(); }

// 实现类按需实现接口
class Human implements Workable, Eatable, Sleepable {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ }
@Override public void sleep() { /* ... */ }
}

class Robot implements Workable { // 机器人无需eat和sleep
@Override public void work() { /* ... */ }
}

优势

  • 减少接口冗余,降低实现类的负担。
  • 避免客户端与无关方法的耦合,提高系统灵活性。

迪米特原则(Law of Demeter, LoD)

核心思想

一个实体应尽可能少地与其他实体发生交互(又称 “最少知识原则”)。
即对象只应与直接朋友(成员变量、方法参数、返回值)通信,避免访问 “朋友的朋友”。

实现方式

  • 减少对象之间的直接依赖,通过中间层(如门面模式)隔离交互。
  • 隐藏内部实现细节,只暴露必要的公共方法。

示例

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
// 违反:直接访问朋友的朋友
class Customer {
void checkOrderStatus(Order order) {
// 直接访问Order的内部对象(ShippingDetails)
String status = order.getShippingDetails().getStatus();
System.out.println(status);
}
}

// 正确:通过朋友(Order)间接访问
class Customer {
void checkOrderStatus(Order order) {
// 调用Order的方法,而非直接访问其内部对象
String status = order.getShippingStatus();
System.out.println(status);
}
}

class Order {
private ShippingDetails shipping;
// 封装内部细节,提供对外方法
public String getShippingStatus() {
return shipping.getStatus();
}
}

优势

  • 降低系统复杂度,减少对象间的耦合。
  • 提高代码的可维护性,避免因一个对象的修改影响多个关联对象。

单一职责原则(Single Responsibility Principle, SRP)

核心思想

一个类或接口只负责一项职责
即一个类应只有一个引起它变化的原因,避免职责混杂导致的维护困难。

违反场景

  • 一个类同时处理数据存储、业务逻辑和 UI 展示。
  • 方法实现多个不相关的功能(如同时处理计算和日志输出)。

示例

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
// 违反:职责混杂(计算+日志)
class Calculator {
public int add(int a, int b) {
int result = a + b;
// 包含日志功能,违反单一职责
logToFile("Result: " + result);
return result;
}
private void logToFile(String message) { /* ... */ }
}

// 正确:拆分职责
class Calculator { // 仅负责计算
public int add(int a, int b) { return a + b; }
}

class Logger { // 仅负责日志
public void log(String message) { /* ... */ }
}

// 客户端组合使用
class Client {
public void calculateAndLog() {
Calculator calc = new Calculator();
Logger logger = new Logger();
int result = calc.add(1, 2);
logger.log("Result: " + result);
}
}

优势

  • 提高类的内聚性,使代码更简洁、易懂。
  • 降低修改风险,一个职责的变化不会影响其他职责。

总结

六大原则的核心目标是降低耦合、提高内聚,构建可扩展、可维护的系统:

  • 开闭原则:扩展优先于修改;
  • 里氏代换:子类替换不影响正确性;
  • 依赖倒转:面向抽象编程;
  • 接口隔离:接口最小化;
  • 迪米特原则:减少交互,弱耦合;
  • 单一职责:职责明确,降低复杂度

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10