一、SOLID原则(核心设计原则)
1. 单一职责原则(Single Responsibility Principle, SRP)
定义:一个类应该只有一个引起它变化的原因,即一个类只负责一项单一的功能。
示例:将User
类拆分为User
(用户信息)和UserService
(用户业务逻辑)
java
// 违反SRP(混合了数据存储和业务逻辑)
class User {
private String name;
public void register() {
// 保存到数据库
saveToDatabase(this);
}
private void saveToDatabase(User user) { ... }
}
// 符合SRP
class User {
private String name;
}
class UserService {
public void register(User user) {
saveToDatabase(user);
}
private void saveToDatabase(User user) { ... }
}
2. 开放封闭原则(Open/Closed Principle, OCP)
定义:软件实体(类、模块、函数)应该对扩展开放,对修改关闭。
示例:通过接口实现图形面积计算,新增图形无需修改现有代码
java
interface Shape {
double area();
}
class Circle implements Shape {
@Override
public double area() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
@Override
public double area() { return length * width; }
}
// 使用方无需修改即可扩展新形状
public class AreaCalculator {
public static double calculateTotal(Shape[] shapes) {
double sum = 0;
for (Shape shape : shapes) sum += shape.area();
return sum;
}
}
3. 里氏替换原则(Liskov Substitution Principle, LSP)
定义:子类必须能够完全替代父类,子类对象出现在父类对象声明的位置时,程序的行为不应发生变化。
示例:Bird
继承Animal
后,不应该出现Bird
无法飞行的异常
java
abstract class Animal {
public void fly() { /* 默认飞行行为 */ }
}
class Penguin extends Animal {
@Override
public void fly() {
throw new UnsupportedOperationException("Penguin can't fly!");
}
}
// 违反LSP:Penguin无法替代Animal的fly方法
4. 接口隔离原则(Interface Segregation Principle, ISP)
定义:客户端不应该被迫依赖它不使用的接口,应将大接口拆分为多个小接口。
示例:将Vehicle
接口拆分为Drivable
和Steerable
java
// 违反ISP(Car实现了不必要的接口)
interface Vehicle {
void drive();
void steer();
void refuel();
}
// 符合ISP
interface Drivable {
void drive();
}
interface Steerable {
void steer();
}
class Car implements Drivable, Steerable {
@Override public void drive() { /* 加速 */ }
@Override public void steer() { /* 转向 */ }
}
5. 依赖倒置原则(Dependency Inversion Principle, DIP)
定义:高层模块不应该依赖低层模块,二者都应依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。
示例:通过构造器注入实现依赖倒置
java
// 违反DIP(高层模块直接依赖具体实现)
class WeatherService {
private DataSource dataSource;
public WeatherService() {
this.dataSource = new MySQLDataSource(); // 直接创建具体对象
}
}
// 符合DIP
interface DataSource {
String getConnection();
}
class MySQLDataSource implements DataSource { ... }
class PostgreSQLDataSource implements DataSource { ... }
class WeatherService {
private final DataSource dataSource;
public WeatherService(DataSource dataSource) {
this.dataSource = dataSource; // 依赖抽象接口
}
}
二、其他重要设计原则
1. 迪米特法则(Law of Demeter, LoD)
定义:一个对象应该对其他对象保持最少的了解,只与直接的朋友通信。
示例:避免在User
类中直接调用Order
类的内部方法
java
class User {
private List<Order> orders;
// 违反LoD:用户不应该知道订单的具体存储方式
public void printOrderDetails() {
for (Order order : orders) {
System.out.println(order.getCustomerId());
System.out.println(order.getItems());
}
}
}
// 改进:通过Order类提供公共接口
class Order {
public String getCustomerId() { ... }
public String getItemsSummary() { ... } // 封装详细信息
}
2. 合成复用原则(Composite Reuse Principle, CRP)
定义:优先使用对象组合而非继承来实现代码复用。
示例:用组合代替继承实现"汽车"功能
java
// 继承方式(难以扩展)
class SportsCar extends Car {
private Turbocharger turbo;
}
// 组合方式(更灵活)
class Car {
private Engine engine;
private Turbocharger turbo;
public Car(Engine engine) {
this.engine = engine;
}
public void addTurbo(Turbocharger turbo) {
this.turbo = turbo;
}
}
三、设计模式与原则的关系
设计模式 | 实现的设计原则 | 典型场景 |
---|---|---|
工厂模式 | OCP, DIP | 对象创建解耦 |
观察者模式 | OCP, SRP | 事件驱动架构 |
策略模式 | OCP, SRP | 动态算法切换 |
适配器模式 | ISP, DIP | 接口兼容 |
装饰器模式 | OCP, SRP | 功能动态扩展 |
四、最佳实践总结
- 优先使用接口:Java中接口支持多继承,适合定义多个独立的行为契约
- 合理使用抽象类:当需要共享部分实现时使用抽象类(Java 8+支持default方法)
- 避免过度设计:遵循YAGNI原则(You Ain't Gonna Need It)
- 代码可读性优先:保持方法单一职责(建议控制在5-10行内)
- 使用设计模式:但不应为了模式而模式化
- 文档化设计决策:通过注释说明关键设计选择
五、反模式警示
- 上帝类(God Class):一个类承担过多职责(如
SystemUtils
包含文件操作、网络请求、数据库操作等) - 字符串拼接地狱:
String result = "Hello " + user.getName() + "!"
→ 改用StringBuilder
- 过度继承:形成长继承链(如
Animal → Mammal → Dog → Labrador
),建议使用组合代替 - 隐藏对象状态:不提供必要的getter/setter方法
java
// 错误示例:暴露内部数据结构
public class User {
public Map<String, String> attributes; // 不安全!
}
// 正确示例:封装属性访问
public class User {
private Map<String, String> attributes;
public String getAttribute(String key) {
return attributes.get(key);
}
public void setAttribute(String key, String value) {
attributes.put(key, value);
}
}
六、实际项目中的权衡
- 性能 vs 可维护性:在高性能场景可能需牺牲部分OOP特性
- 团队协作:复杂的设计模式可能增加团队理解成本
- 框架限制:某些框架(如Spring Boot)会预设设计模式
- 技术债务:短期快速交付可能需要简化设计
通过系统应用这些设计原则,可以构建出高内聚、低耦合、易扩展的软件系统。记住:原则是指导方针而非铁律,实际开发中需要根据具体场景灵活平衡。