solid-principles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSOLID Principles Skill
SOLID原则使用指南
Review and apply SOLID principles in Java code.
用于评审Java代码并应用SOLID原则。
When to Use
适用场景
- User says "check SOLID" / "SOLID review" / "is this class doing too much?"
- Reviewing class design
- Refactoring large classes
- Code review focusing on design
- 用户提到「检查SOLID」/「SOLID评审」/「这个类是不是承担了太多职责?」
- 类设计评审
- 大型类重构
- 聚焦设计的代码评审
Quick Reference
速查参考
| Letter | Principle | One-liner |
|---|---|---|
| S | Single Responsibility | One class = one reason to change |
| O | Open/Closed | Open for extension, closed for modification |
| L | Liskov Substitution | Subtypes must be substitutable for base types |
| I | Interface Segregation | Many specific interfaces > one general interface |
| D | Dependency Inversion | Depend on abstractions, not concretions |
| 字母 | 原则 | 一句话总结 |
|---|---|---|
| S | 单一职责原则 | 一个类只有一个需要变更的理由 |
| O | 开闭原则 | 对扩展开放,对修改关闭 |
| L | 里氏替换原则 | 子类必须可以替换其基类使用 |
| I | 接口隔离原则 | 多个专用接口优于一个通用接口 |
| D | 依赖倒置原则 | 依赖抽象,而非具体实现 |
S - Single Responsibility Principle (SRP)
S - 单一职责原则 (SRP)
"A class should have only one reason to change."
「一个类应该只有一个变更的理由。」
Violation
违反示例
java
// ❌ BAD: UserService does too much
public class UserService {
public User createUser(String name, String email) {
// validation logic
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
// persistence logic
User user = new User(name, email);
entityManager.persist(user);
// notification logic
String subject = "Welcome!";
String body = "Hello " + name;
emailClient.send(email, subject, body);
// audit logic
auditLog.log("User created: " + email);
return user;
}
}Problems:
- Validation changes? Modify UserService
- Email template changes? Modify UserService
- Audit format changes? Modify UserService
- Hard to test each concern separately
java
// ❌ 错误:UserService承担了太多职责
public class UserService {
public User createUser(String name, String email) {
// 校验逻辑
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
// 持久化逻辑
User user = new User(name, email);
entityManager.persist(user);
// 通知逻辑
String subject = "Welcome!";
String body = "Hello " + name;
emailClient.send(email, subject, body);
// 审计逻辑
auditLog.log("User created: " + email);
return user;
}
}问题:
- 校验规则变更?需要修改UserService
- 邮件模板变更?需要修改UserService
- 审计格式变更?需要修改UserService
- 难以单独测试每个职责模块
Refactored
重构后
java
// ✅ GOOD: Each class has one responsibility
public class UserValidator {
public void validate(String name, String email) {
if (email == null || !email.contains("@")) {
throw new ValidationException("Invalid email");
}
}
}
public class UserRepository {
public User save(User user) {
entityManager.persist(user);
return user;
}
}
public class WelcomeEmailSender {
public void sendWelcome(User user) {
String subject = "Welcome!";
String body = "Hello " + user.getName();
emailClient.send(user.getEmail(), subject, body);
}
}
public class UserAuditLogger {
public void logCreation(User user) {
auditLog.log("User created: " + user.getEmail());
}
}
public class UserService {
private final UserValidator validator;
private final UserRepository repository;
private final WelcomeEmailSender emailSender;
private final UserAuditLogger auditLogger;
public User createUser(String name, String email) {
validator.validate(name, email);
User user = repository.save(new User(name, email));
emailSender.sendWelcome(user);
auditLogger.logCreation(user);
return user;
}
}java
// ✅ 正确:每个类仅承担一项职责
public class UserValidator {
public void validate(String name, String email) {
if (email == null || !email.contains("@")) {
throw new ValidationException("Invalid email");
}
}
}
public class UserRepository {
public User save(User user) {
entityManager.persist(user);
return user;
}
}
public class WelcomeEmailSender {
public void sendWelcome(User user) {
String subject = "Welcome!";
String body = "Hello " + user.getName();
emailClient.send(user.getEmail(), subject, body);
}
}
public class UserAuditLogger {
public void logCreation(User user) {
auditLog.log("User created: " + user.getEmail());
}
}
public class UserService {
private final UserValidator validator;
private final UserRepository repository;
private final WelcomeEmailSender emailSender;
private final UserAuditLogger auditLogger;
public User createUser(String name, String email) {
validator.validate(name, email);
User user = repository.save(new User(name, email));
emailSender.sendWelcome(user);
auditLogger.logCreation(user);
return user;
}
}How to Detect SRP Violations
如何检测SRP违反
- Class has many statements from different domains
import - Class name contains "And" or "Manager" or "Handler" (often)
- Methods operate on unrelated data
- Changes in one area require touching unrelated methods
- Hard to name the class concisely
- 类导入了多个不同领域的包
- 类名包含「And」、「Manager」或「Handler」(常见情况)
- 方法操作无关联的数据
- 某一领域的变更需要修改无关的方法
- 难以用简洁的语句描述类的用途
Quick Check Questions
快速检查问题
- Can you describe the class purpose in one sentence without "and"?
- Would different stakeholders request changes to this class?
- Are there methods that don't use most of the class fields?
- 你能否不用「和」字,用一句话描述类的用途?
- 不同的业务方是否都会要求修改这个类?
- 是否存在方法几乎不使用类的大部分字段?
O - Open/Closed Principle (OCP)
O - 开闭原则 (OCP)
"Software entities should be open for extension, but closed for modification."
「软件实体应该对扩展开放,对修改关闭。」
Violation
违反示例
java
// ❌ BAD: Must modify class to add new discount type
public class DiscountCalculator {
public double calculate(Order order, String discountType) {
if (discountType.equals("PERCENTAGE")) {
return order.getTotal() * 0.1;
} else if (discountType.equals("FIXED")) {
return 50.0;
} else if (discountType.equals("LOYALTY")) {
return order.getTotal() * order.getCustomer().getLoyaltyRate();
}
// Every new discount type = modify this class
return 0;
}
}java
// ❌ 错误:新增折扣类型必须修改现有类
public class DiscountCalculator {
public double calculate(Order order, String discountType) {
if (discountType.equals("PERCENTAGE")) {
return order.getTotal() * 0.1;
} else if (discountType.equals("FIXED")) {
return 50.0;
} else if (discountType.equals("LOYALTY")) {
return order.getTotal() * order.getCustomer().getLoyaltyRate();
}
// 每新增一种折扣类型都要修改这个类
return 0;
}
}Refactored
重构后
java
// ✅ GOOD: Add new discounts without modifying existing code
public interface DiscountStrategy {
double calculate(Order order);
boolean supports(String discountType);
}
public class PercentageDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * 0.1;
}
@Override
public boolean supports(String discountType) {
return "PERCENTAGE".equals(discountType);
}
}
public class FixedDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return 50.0;
}
@Override
public boolean supports(String discountType) {
return "FIXED".equals(discountType);
}
}
public class LoyaltyDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * order.getCustomer().getLoyaltyRate();
}
@Override
public boolean supports(String discountType) {
return "LOYALTY".equals(discountType);
}
}
// New discount? Just add new class, no modification needed
public class SeasonalDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * 0.2;
}
@Override
public boolean supports(String discountType) {
return "SEASONAL".equals(discountType);
}
}
public class DiscountCalculator {
private final List<DiscountStrategy> strategies;
public DiscountCalculator(List<DiscountStrategy> strategies) {
this.strategies = strategies;
}
public double calculate(Order order, String discountType) {
return strategies.stream()
.filter(s -> s.supports(discountType))
.findFirst()
.map(s -> s.calculate(order))
.orElse(0.0);
}
}java
// ✅ 正确:无需修改现有代码即可新增折扣类型
public interface DiscountStrategy {
double calculate(Order order);
boolean supports(String discountType);
}
public class PercentageDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * 0.1;
}
@Override
public boolean supports(String discountType) {
return "PERCENTAGE".equals(discountType);
}
}
public class FixedDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return 50.0;
}
@Override
public boolean supports(String discountType) {
return "FIXED".equals(discountType);
}
}
public class LoyaltyDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * order.getCustomer().getLoyaltyRate();
}
@Override
public boolean supports(String discountType) {
return "LOYALTY".equals(discountType);
}
}
// 新增折扣?只需新增类,无需修改现有代码
public class SeasonalDiscount implements DiscountStrategy {
@Override
public double calculate(Order order) {
return order.getTotal() * 0.2;
}
@Override
public boolean supports(String discountType) {
return "SEASONAL".equals(discountType);
}
}
public class DiscountCalculator {
private final List<DiscountStrategy> strategies;
public DiscountCalculator(List<DiscountStrategy> strategies) {
this.strategies = strategies;
}
public double calculate(Order order, String discountType) {
return strategies.stream()
.filter(s -> s.supports(discountType))
.findFirst()
.map(s -> s.calculate(order))
.orElse(0.0);
}
}How to Detect OCP Violations
如何检测OCP违反
- or
if/elseon type/status that grows over timeswitch - Enum-based dispatching with frequent new values
- Changes require modifying core classes
- 基于类型/状态的或
if/else分支持续增加switch - 基于枚举的分发逻辑频繁新增枚举值
- 功能变更需要修改核心类
Common OCP Patterns
常见OCP适配模式
| Pattern | Use When |
|---|---|
| Strategy | Multiple algorithms for same operation |
| Template Method | Same structure, different steps |
| Decorator | Add behavior dynamically |
| Factory | Create objects without specifying class |
| 模式 | 适用场景 |
|---|---|
| 策略模式 | 同一操作存在多种算法实现 |
| 模板方法模式 | 流程结构相同,具体步骤不同 |
| 装饰器模式 | 动态新增行为 |
| 工厂模式 | 无需指定类即可创建对象 |
L - Liskov Substitution Principle (LSP)
L - 里氏替换原则 (LSP)
"Subtypes must be substitutable for their base types."
「子类必须可以替换其基类使用。」
Violation
违反示例
java
// ❌ BAD: Square violates Rectangle contract
public class Rectangle {
protected int width;
protected int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int getArea() {
return width * height;
}
}
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // Violates expected behavior!
}
@Override
public void setHeight(int height) {
this.width = height; // Violates expected behavior!
this.height = height;
}
}
// This test fails for Square!
void testRectangle(Rectangle r) {
r.setWidth(5);
r.setHeight(4);
assert r.getArea() == 20; // Square returns 16!
}java
// ❌ 错误:Square违反了Rectangle的契约
public class Rectangle {
protected int width;
protected int height;
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int getArea() {
return width * height;
}
}
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // 违反了预期行为!
}
@Override
public void setHeight(int height) {
this.width = height; // 违反了预期行为!
this.height = height;
}
}
// 该测试用例传入Square时会失败!
void testRectangle(Rectangle r) {
r.setWidth(5);
r.setHeight(4);
assert r.getArea() == 20; // Square会返回16!
}Refactored
重构后
java
// ✅ GOOD: Separate abstractions
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
private final int width;
private final int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public int getArea() {
return width * height;
}
}
public class Square implements Shape {
private final int side;
public Square(int side) {
this.side = side;
}
@Override
public int getArea() {
return side * side;
}
}java
// ✅ 正确:拆分抽象
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
private final int width;
private final int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public int getArea() {
return width * height;
}
}
public class Square implements Shape {
private final int side;
public Square(int side) {
this.side = side;
}
@Override
public int getArea() {
return side * side;
}
}LSP Rules
LSP规则
| Rule | Meaning |
|---|---|
| Preconditions | Subclass cannot strengthen (require more) |
| Postconditions | Subclass cannot weaken (promise less) |
| Invariants | Subclass must maintain parent's invariants |
| History | Subclass cannot modify inherited state unexpectedly |
| 规则 | 含义 |
|---|---|
| 前置条件 | 子类不能强化前置条件(不能要求更多入参/限制) |
| 后置条件 | 子类不能弱化后置条件(不能减少承诺的输出) |
| 不变量 | 子类必须维护父类的不变量 |
| 历史约束 | 子类不能意外修改继承的状态 |
How to Detect LSP Violations
如何检测LSP违反
- Subclass throws exception parent doesn't
- Subclass returns null where parent returns object
- Subclass ignores or overrides parent behavior unexpectedly
- checks before calling methods
instanceof - Empty or throwing implementations of interface methods
- 子类抛出父类不会抛出的异常
- 子类在父类返回对象的场景返回null
- 子类意外忽略或重写父类行为
- 调用方法前需要做检查
instanceof - 接口方法的实现为空或直接抛出异常
Quick Check
快速检查
java
// If you see this, LSP might be violated
if (bird instanceof Penguin) {
// don't call fly()
} else {
bird.fly();
}java
// 如果你看到这种代码,很可能违反了LSP
if (bird instanceof Penguin) {
// 不要调用fly()
} else {
bird.fly();
}I - Interface Segregation Principle (ISP)
I - 接口隔离原则 (ISP)
"Clients should not be forced to depend on interfaces they do not use."
「不应该强迫客户端依赖它们不需要使用的接口。」
Violation
违反示例
java
// ❌ BAD: Fat interface forces unnecessary implementations
public interface Worker {
void work();
void eat();
void sleep();
void attendMeeting();
void writeReport();
}
// Robot can't eat or sleep!
public class Robot implements Worker {
@Override public void work() { /* OK */ }
@Override public void eat() { /* Can't eat! */ }
@Override public void sleep() { /* Can't sleep! */ }
@Override public void attendMeeting() { /* OK */ }
@Override public void writeReport() { /* Maybe */ }
}
// Intern doesn't attend meetings or write reports
public class Intern implements Worker {
@Override public void work() { /* OK */ }
@Override public void eat() { /* OK */ }
@Override public void sleep() { /* OK */ }
@Override public void attendMeeting() { /* Not allowed! */ }
@Override public void writeReport() { /* Not expected! */ }
}java
// ❌ 错误:臃肿的接口强制实现不需要的方法
public interface Worker {
void work();
void eat();
void sleep();
void attendMeeting();
void writeReport();
}
// 机器人不能吃饭睡觉!
public class Robot implements Worker {
@Override public void work() { /* 正常实现 */ }
@Override public void eat() { /* 无法实现 */ }
@Override public void sleep() { /* 无法实现 */ }
@Override public void attendMeeting() { /* 正常实现 */ }
@Override public void writeReport() { /* 可能实现 */ }
}
// 实习生不需要参会或写报告
public class Intern implements Worker {
@Override public void work() { /* 正常实现 */ }
@Override public void eat() { /* 正常实现 */ }
@Override public void sleep() { /* 正常实现 */ }
@Override public void attendMeeting() { /* 无权限 */ }
@Override public void writeReport() { /* 无要求 */ }
}Refactored
重构后
java
// ✅ GOOD: Segregated interfaces
public interface Workable {
void work();
}
public interface Feedable {
void eat();
void sleep();
}
public interface Manageable {
void attendMeeting();
void writeReport();
}
// Combine what you need
public class Employee implements Workable, Feedable, Manageable {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ }
@Override public void sleep() { /* ... */ }
@Override public void attendMeeting() { /* ... */ }
@Override public void writeReport() { /* ... */ }
}
public class Robot implements Workable {
@Override public void work() { /* ... */ }
// No unnecessary methods!
}
public class Intern implements Workable, Feedable {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ }
@Override public void sleep() { /* ... */ }
// No meeting/report methods!
}java
// ✅ 正确:拆分后的细粒度接口
public interface Workable {
void work();
}
public interface Feedable {
void eat();
void sleep();
}
public interface Manageable {
void attendMeeting();
void writeReport();
}
// 按需组合接口
public class Employee implements Workable, Feedable, Manageable {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ }
@Override public void sleep() { /* ... */ }
@Override public void attendMeeting() { /* ... */ }
@Override public void writeReport() { /* ... */ }
}
public class Robot implements Workable {
@Override public void work() { /* ... */ }
// 没有多余的方法!
}
public class Intern implements Workable, Feedable {
@Override public void work() { /* ... */ }
@Override public void eat() { /* ... */ }
@Override public void sleep() { /* ... */ }
// 没有参会/写报告的方法!
}How to Detect ISP Violations
如何检测ISP违反
- Implementations with empty methods or
throw new UnsupportedOperationException() - Interface has 10+ methods
- Different clients use completely different subsets of methods
- Changes to interface affect unrelated implementations
- 实现类存在空方法或抛出
UnsupportedOperationException - 接口包含10个以上方法
- 不同客户端使用接口完全不重叠的方法子集
- 接口变更会影响无关的实现类
Java Standard Library Violations
Java标准库中的ISP违反示例
java
// java.util.List has many methods - but this is acceptable for collections
// However, be careful with your own interfaces!
// ❌ This interface is too fat for most use cases
public interface Repository<T> {
T findById(Long id);
List<T> findAll();
T save(T entity);
void delete(T entity);
void deleteById(Long id);
List<T> findByExample(T example);
Page<T> findAll(Pageable pageable);
List<T> findAllById(Iterable<Long> ids);
long count();
boolean existsById(Long id);
// ... 20 more methods
}
// ✅ Better: Split by use case
public interface ReadRepository<T> {
Optional<T> findById(Long id);
List<T> findAll();
}
public interface WriteRepository<T> {
T save(T entity);
void delete(T entity);
}java
// java.util.List包含很多方法 - 但对于集合框架来说是可接受的
// 但自己定义接口时要注意避免臃肿!
// ❌ 这个接口对于大多数场景来说过于臃肿
public interface Repository<T> {
T findById(Long id);
List<T> findAll();
T save(T entity);
void delete(T entity);
void deleteById(Long id);
List<T> findByExample(T example);
Page<T> findAll(Pageable pageable);
List<T> findAllById(Iterable<Long> ids);
long count();
boolean existsById(Long id);
// ... 还有20多个方法
}
// ✅ 更好的做法:按使用场景拆分
public interface ReadRepository<T> {
Optional<T> findById(Long id);
List<T> findAll();
}
public interface WriteRepository<T> {
T save(T entity);
void delete(T entity);
}D - Dependency Inversion Principle (DIP)
D - 依赖倒置原则 (DIP)
"High-level modules should not depend on low-level modules. Both should depend on abstractions."
「高层模块不应该依赖低层模块,二者都应该依赖抽象。」
Violation
违反示例
java
// ❌ BAD: High-level depends on low-level directly
public class OrderService {
private MySqlOrderRepository repository; // Concrete class!
private SmtpEmailSender emailSender; // Concrete class!
public OrderService() {
this.repository = new MySqlOrderRepository(); // Hard dependency
this.emailSender = new SmtpEmailSender(); // Hard dependency
}
public void createOrder(Order order) {
repository.save(order);
emailSender.send(order.getCustomerEmail(), "Order confirmed");
}
}Problems:
- Cannot test without real MySQL database
- Cannot swap email provider
- OrderService knows about MySQL, SMTP details
java
// ❌ 错误:高层模块直接依赖低层具体实现
public class OrderService {
private MySqlOrderRepository repository; // 具体实现类!
private SmtpEmailSender emailSender; // 具体实现类!
public OrderService() {
this.repository = new MySqlOrderRepository(); // 硬编码依赖
this.emailSender = new SmtpEmailSender(); // 硬编码依赖
}
public void createOrder(Order order) {
repository.save(order);
emailSender.send(order.getCustomerEmail(), "Order confirmed");
}
}问题:
- 没有真实MySQL数据库就无法测试
- 无法更换邮件服务提供商
- OrderService感知到了MySQL、SMTP的实现细节
Refactored
重构后
java
// ✅ GOOD: Depend on abstractions
// Abstractions (interfaces)
public interface OrderRepository {
void save(Order order);
Optional<Order> findById(Long id);
}
public interface NotificationSender {
void send(String recipient, String message);
}
// High-level module depends on abstractions
public class OrderService {
private final OrderRepository repository;
private final NotificationSender notificationSender;
// Dependencies injected
public OrderService(OrderRepository repository,
NotificationSender notificationSender) {
this.repository = repository;
this.notificationSender = notificationSender;
}
public void createOrder(Order order) {
repository.save(order);
notificationSender.send(order.getCustomerEmail(), "Order confirmed");
}
}
// Low-level modules implement abstractions
public class MySqlOrderRepository implements OrderRepository {
@Override
public void save(Order order) { /* MySQL specific */ }
@Override
public Optional<Order> findById(Long id) { /* MySQL specific */ }
}
public class SmtpEmailSender implements NotificationSender {
@Override
public void send(String recipient, String message) { /* SMTP specific */ }
}
// Easy to test with mocks!
public class InMemoryOrderRepository implements OrderRepository {
private Map<Long, Order> orders = new HashMap<>();
@Override
public void save(Order order) {
orders.put(order.getId(), order);
}
@Override
public Optional<Order> findById(Long id) {
return Optional.ofNullable(orders.get(id));
}
}java
// ✅ 正确:依赖抽象
// 抽象(接口)
public interface OrderRepository {
void save(Order order);
Optional<Order> findById(Long id);
}
public interface NotificationSender {
void send(String recipient, String message);
}
// 高层模块依赖抽象
public class OrderService {
private final OrderRepository repository;
private final NotificationSender notificationSender;
// 依赖注入
public OrderService(OrderRepository repository,
NotificationSender notificationSender) {
this.repository = repository;
this.notificationSender = notificationSender;
}
public void createOrder(Order order) {
repository.save(order);
notificationSender.send(order.getCustomerEmail(), "订单已确认");
}
}
// 低层模块实现抽象
public class MySqlOrderRepository implements OrderRepository {
@Override
public void save(Order order) { /* MySQL专属实现 */ }
@Override
public Optional<Order> findById(Long id) { /* MySQL专属实现 */ }
}
public class SmtpEmailSender implements NotificationSender {
@Override
public void send(String recipient, String message) { /* SMTP专属实现 */ }
}
// 可以很方便地用Mock实现测试
public class InMemoryOrderRepository implements OrderRepository {
private Map<Long, Order> orders = new HashMap<>();
@Override
public void save(Order order) {
orders.put(order.getId(), order);
}
@Override
public Optional<Order> findById(Long id) {
return Optional.ofNullable(orders.get(id));
}
}DIP with Spring
Spring中DIP的应用
java
// Spring handles dependency injection automatically
@Service
public class OrderService {
private final OrderRepository repository;
private final NotificationSender notificationSender;
// Constructor injection (recommended)
public OrderService(OrderRepository repository,
NotificationSender notificationSender) {
this.repository = repository;
this.notificationSender = notificationSender;
}
}
@Repository
public class JpaOrderRepository implements OrderRepository {
// Spring provides implementation
}
@Component
@Profile("production")
public class SmtpEmailSender implements NotificationSender { }
@Component
@Profile("test")
public class MockEmailSender implements NotificationSender { }java
// Spring自动处理依赖注入
@Service
public class OrderService {
private final OrderRepository repository;
private final NotificationSender notificationSender;
// 构造器注入(推荐做法)
public OrderService(OrderRepository repository,
NotificationSender notificationSender) {
this.repository = repository;
this.notificationSender = notificationSender;
}
}
@Repository
public class JpaOrderRepository implements OrderRepository {
// Spring自动提供实现
}
@Component
@Profile("production")
public class SmtpEmailSender implements NotificationSender { }
@Component
@Profile("test")
public class MockEmailSender implements NotificationSender { }How to Detect DIP Violations
如何检测DIP违反
- inside business logic
new ConcreteClass() - Import statements include implementation packages (e.g., ,
com.mysql)org.apache.http - Cannot easily swap implementations
- Tests require real infrastructure (database, network)
- 业务逻辑中存在的代码
new 具体类() - 导入了实现类所在的包(例如、
com.mysql)org.apache.http - 无法轻松替换实现类
- 测试需要依赖真实的基础设施(数据库、网络)
SOLID Review Checklist
SOLID评审检查清单
When reviewing code, check:
| Principle | Question |
|---|---|
| SRP | Does this class have more than one reason to change? |
| OCP | Will adding a new type/feature require modifying this class? |
| LSP | Can subclasses be used wherever parent is expected? |
| ISP | Are there empty or throwing method implementations? |
| DIP | Does high-level code depend on concrete implementations? |
评审代码时可检查以下问题:
| 原则 | 检查问题 |
|---|---|
| SRP | 这个类是否有多个变更的理由? |
| OCP | 新增类型/功能是否需要修改这个类? |
| LSP | 子类是否可以在所有使用父类的场景下替换父类? |
| ISP | 是否存在空实现或抛出异常的方法? |
| DIP | 高层代码是否依赖了具体实现类? |
Common Refactoring Patterns
常见重构模式
| Violation | Refactoring |
|---|---|
| SRP - God class | Extract Class, Move Method |
| OCP - Type switching | Strategy Pattern, Factory |
| LSP - Broken inheritance | Composition over Inheritance, Extract Interface |
| ISP - Fat interface | Split Interface, Role Interface |
| DIP - Hard dependencies | Dependency Injection, Abstract Factory |
| 违反场景 | 重构方案 |
|---|---|
| SRP - 上帝类 | 提取类、移动方法 |
| OCP - 类型分支判断 | 策略模式、工厂模式 |
| LSP - 继承契约被破坏 | 组合优于继承、提取接口 |
| ISP - 臃肿接口 | 拆分接口、角色接口 |
| DIP - 硬编码依赖 | 依赖注入、抽象工厂 |
Related Skills
相关技能
- - Implementation patterns (Factory, Strategy, Observer, etc.)
design-patterns - - Code-level principles (DRY, KISS, naming)
clean-code - - Comprehensive review checklist
java-code-review
- - 实现模式(工厂、策略、观察者等)
design-patterns - - 代码层面原则(DRY、KISS、命名规范)
clean-code - - 全面的代码评审检查清单
java-code-review