软件架构设计7大原则
设计原则
- 1. 开闭原则(OCP - Open-Closed Principle)
- 2. 单一职责原则(SRP - Single Responsibility Principle)
- 3. 里氏替换原则(LSP - Liskov Substitution Principle)
- 4. 依赖倒置原则(DIP - Dependency Inversion Principle)
- 5. 接口隔离原则(ISP - Interface Segregation Principle)
- 6. 迪米特法则(LoD - Law of Demeter)
- 7. 组合优于继承(Composition Over Inheritance)
- 总结
在Java软件开发中,有7大重要的设计原则,它们帮助开发者编写高内聚、低耦合、可维护、可扩展的代码。这些原则也被称为SOLID原则 + 其他关键设计原则,它们是面向对象编程(OOP)和软件架构的核心。
- 高内聚
- 低耦合
- 可维护
- 可扩展
1. 开闭原则(OCP - Open-Closed Principle)
定义:
对扩展开放,对修改关闭。
含义:
- 软件应该可以扩展新功能,而不应该修改已有代码。
- 使用接口、抽象类、策略模式等方式来实现扩展。
示例:
// 定义抽象接口,避免修改原有代码
interface Shape {
double calculateArea();
}
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public double calculateArea() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
private double width, height;
public Rectangle(double width, double height) { this.width = width; this.height = height; }
@Override
public double calculateArea() { return width * height; }
}
✅ 好处: 新增 Triangle
(三角形)时,只需实现 Shape
接口,不用修改原代码,符合开闭原则。
2. 单一职责原则(SRP - Single Responsibility Principle)
定义:
一个类应该只有一个引起它变化的原因。
含义:
- 每个类 只负责 一个功能,避免过多职责耦合。
- 增强代码的可读性、可维护性。
示例(违反单一职责):
class ReportManager {
void generateReport() { /* 生成报表的逻辑 */ }
void saveToDatabase() { /* 数据库存储逻辑 */ }
void sendEmail() { /* 发送邮件逻辑 */ }
}
✅ 遵循单一职责原则(拆分成多个类):
class ReportGenerator {
void generateReport() { /* 生成报表 */ }
}
class DatabaseSaver {
void saveToDatabase() { /* 存储数据 */ }
}
class EmailSender {
void sendEmail() { /* 发送邮件 */ }
}
好处: 各个类职责单一,避免代码臃肿、难维护。
3. 里氏替换原则(LSP - Liskov Substitution Principle)
定义:
子类可以替换父类,并且不会影响父类的功能。
含义:
- 子类应该能够扩展父类的功能,而不会改变父类的行为。
- 不能让子类破坏父类的逻辑,否则多态会失效。
示例(违反LSP):
class Bird {
void fly() { System.out.println("Bird is flying"); }
}
class Penguin extends Bird { // 企鹅不会飞
@Override
void fly() { throw new UnsupportedOperationException("Penguin cannot fly!"); }
}
✅ 遵循LSP(重构):
interface Bird { }
interface FlyableBird extends Bird {
void fly();
}
class Sparrow implements FlyableBird {
@Override
public void fly() { System.out.println("Sparrow is flying"); }
}
class Penguin implements Bird { /* 企鹅不会飞 */ }
好处: 避免子类破坏父类逻辑,保证多态的正确性。
4. 依赖倒置原则(DIP - Dependency Inversion Principle)
定义:
高层模块不应该依赖于低层模块,而应该依赖于抽象。
含义:
- 上层代码 不依赖于 具体实现(类),而是依赖 接口或抽象类。
- 低层代码 也依赖 接口,而不是直接实现。
示例(违反DIP):
class MySQLDatabase {
void connect() { System.out.println("Connecting to MySQL"); }
}
class Application {
private MySQLDatabase database = new MySQLDatabase();
void start() { database.connect(); }
}
✅ 遵循DIP(使用接口):
interface Database {
void connect();
}
class MySQLDatabase implements Database {
@Override
public void connect() { System.out.println("Connecting to MySQL"); }
}
class Application {
private Database database;
public Application(Database database) { this.database = database; }
void start() { database.connect(); }
}
好处:
- 未来如果更换
PostgreSQLDatabase
,无需修改Application
代码,增强灵活性。
5. 接口隔离原则(ISP - Interface Segregation Principle)
定义:
接口应该尽可能小,每个接口只定义特定功能,而不是一个大而全的接口。
含义:
- 避免“胖接口”,不让类实现它们不需要的方法。
- 通过多个小接口,提供更清晰的抽象。
示例(违反ISP):
interface Animal {
void eat();
void fly();
void swim();
}
class Dog implements Animal {
public void eat() { /* 正常实现 */ }
public void fly() { throw new UnsupportedOperationException(); } // 不需要
public void swim() { /* 正常实现 */ }
}
✅ 遵循ISP(拆分接口):
interface Eater { void eat(); }
interface Flyer { void fly(); }
interface Swimmer { void swim(); }
class Dog implements Eater, Swimmer {
public void eat() { /* 正常实现 */ }
public void swim() { /* 正常实现 */ }
}
好处: 避免不必要的方法实现,提高代码灵活性。
6. 迪米特法则(LoD - Law of Demeter)
定义:
一个类应该尽可能少地与其他类发生直接交互。
含义:
- 最小知识原则(Least Knowledge Principle, LKP):一个对象应尽量减少对其他对象的依赖。
- 降低耦合度,减少不必要的依赖。
示例(违反LoD):
class Engine {
void start() { System.out.println("Engine starting..."); }
}
class Car {
Engine engine = new Engine();
void start() { engine.start(); } // 直接访问Engine
}
✅ 遵循LoD(使用封装):
class Engine {
void start() { System.out.println("Engine starting..."); }
}
class Car {
private Engine engine = new Engine();
void startCar() { engine.start(); } // 间接访问
}
好处: 避免暴露不必要的内部实现,降低代码耦合度。
7. 组合优于继承(Composition Over Inheritance)
定义:
优先使用“组合”来实现代码复用,而不是继承。
含义:
- 继承耦合度高,父类变化会影响子类。
- 使用组合(has-a关系)更灵活,可以在运行时动态替换组件。
✅ 示例(组合替代继承):
class Engine {
void start() { System.out.println("Engine starting..."); }
}
class Car {
private Engine engine;
Car(Engine engine) { this.engine = engine; }
void startCar() { engine.start(); }
}
好处: 增强灵活性,避免继承带来的复杂依赖。
总结
原则 | 核心思想 |
---|---|
OCP | 开闭原则:对扩展开放,对修改关闭 |
SRP | 单一职责:一个类只做一件事 |
LSP | 里氏替换:子类可以替换父类 |
DIP | 依赖倒置:依赖抽象而非具体实现 |
ISP | 接口隔离:接口要小而精,不要臃肿 |
LoD | 迪米特法则:减少耦合,少与其他类交互 |
组合优于继承 | 使用组合代替继承,增强灵活性 |
熟练掌握这些原则,可以帮助你写出更灵活、可维护、可扩展的Java代码! 🚀