solid-principles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSOLID Principles for .NET
.NET中的SOLID原则
Overview
概述
SOLID is an acronym for five principles that lead to maintainable, testable, and extensible object-oriented code.
| Principle | Summary |
|---|---|
| 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 |
SOLID是一组面向对象设计原则的首字母缩写词,遵循这些原则可打造具备可维护性、可测试性和可扩展性的代码。
| 原则 | 概述 |
|---|---|
| S - 单一职责原则(Single Responsibility) | 一个类,一个修改理由 |
| O - 开闭原则(Open/Closed) | 对扩展开放,对修改关闭 |
| L - 里氏替换原则(Liskov Substitution) | 子类必须能够替换其基类 |
| I - 接口隔离原则(Interface Segregation) | 多个专用接口优于一个通用接口 |
| D - 依赖倒置原则(Dependency Inversion) | 依赖抽象,而非具体实现 |
S - Single Responsibility Principle (SRP)
S - 单一职责原则(SRP)
A class should have only one reason to change.
一个类应该只有一个被修改的理由。
Violation Example
反例
csharp
// BAD: Multiple responsibilities
public class OrderService
{
public Order CreateOrder(OrderRequest request)
{
// Validation logic
if (string.IsNullOrEmpty(request.CustomerEmail))
throw new ValidationException("Email required");
// Business logic
var order = new Order
{
Id = Guid.NewGuid(),
Items = request.Items,
Total = CalculateTotal(request.Items)
};
// Persistence logic
using var connection = new SqlConnection(_connectionString);
connection.Execute("INSERT INTO Orders...", order);
// Notification logic
var emailBody = $"Order {order.Id} confirmed!";
_smtpClient.Send(request.CustomerEmail, "Order Confirmed", emailBody);
// Logging logic
File.AppendAllText("orders.log", $"{DateTime.Now}: Order {order.Id} created");
return order;
}
}csharp
// 不良示例:承担多个职责
public class OrderService
{
public Order CreateOrder(OrderRequest request)
{
// 验证逻辑
if (string.IsNullOrEmpty(request.CustomerEmail))
throw new ValidationException("Email required");
// 业务逻辑
var order = new Order
{
Id = Guid.NewGuid(),
Items = request.Items,
Total = CalculateTotal(request.Items)
};
// 持久化逻辑
using var connection = new SqlConnection(_connectionString);
connection.Execute("INSERT INTO Orders...", order);
// 通知逻辑
var emailBody = $"Order {order.Id} confirmed!";
_smtpClient.Send(request.CustomerEmail, "Order Confirmed", emailBody);
// 日志逻辑
File.AppendAllText("orders.log", $"{DateTime.Now}: Order {order.Id} created");
return order;
}
}Correct Implementation
正确实现
csharp
// GOOD: Single responsibility per class
public class OrderService
{
private readonly IOrderValidator _validator;
private readonly IOrderRepository _repository;
private readonly IOrderNotifier _notifier;
private readonly ILogger<OrderService> _logger;
public OrderService(
IOrderValidator validator,
IOrderRepository repository,
IOrderNotifier notifier,
ILogger<OrderService> logger)
{
_validator = validator;
_repository = repository;
_notifier = notifier;
_logger = logger;
}
public async Task<Order> CreateOrderAsync(OrderRequest request)
{
_validator.Validate(request);
var order = Order.Create(request.Items);
await _repository.AddAsync(order);
await _notifier.NotifyOrderCreatedAsync(order, request.CustomerEmail);
_logger.LogInformation("Order {OrderId} created", order.Id);
return order;
}
}
// Each concern in its own class
public class OrderValidator : IOrderValidator
{
public void Validate(OrderRequest request)
{
if (string.IsNullOrEmpty(request.CustomerEmail))
throw new ValidationException("Email required");
}
}
public class OrderRepository : IOrderRepository
{
private readonly DbContext _context;
public async Task AddAsync(Order order)
{
_context.Orders.Add(order);
await _context.SaveChangesAsync();
}
}
public class EmailOrderNotifier : IOrderNotifier
{
private readonly IEmailService _emailService;
public async Task NotifyOrderCreatedAsync(Order order, string email)
{
await _emailService.SendAsync(email, "Order Confirmed", $"Order {order.Id} confirmed!");
}
}csharp
// 良好示例:每个类单一职责
public class OrderService
{
private readonly IOrderValidator _validator;
private readonly IOrderRepository _repository;
private readonly IOrderNotifier _notifier;
private readonly ILogger<OrderService> _logger;
public OrderService(
IOrderValidator validator,
IOrderRepository repository,
IOrderNotifier notifier,
ILogger<OrderService> logger)
{
_validator = validator;
_repository = repository;
_notifier = notifier;
_logger = logger;
}
public async Task<Order> CreateOrderAsync(OrderRequest request)
{
_validator.Validate(request);
var order = Order.Create(request.Items);
await _repository.AddAsync(order);
await _notifier.NotifyOrderCreatedAsync(order, request.CustomerEmail);
_logger.LogInformation("Order {OrderId} created", order.Id);
return order;
}
}
// 每个关注点独立成类
public class OrderValidator : IOrderValidator
{
public void Validate(OrderRequest request)
{
if (string.IsNullOrEmpty(request.CustomerEmail))
throw new ValidationException("Email required");
}
}
public class OrderRepository : IOrderRepository
{
private readonly DbContext _context;
public async Task AddAsync(Order order)
{
_context.Orders.Add(order);
await _context.SaveChangesAsync();
}
}
public class EmailOrderNotifier : IOrderNotifier
{
private readonly IEmailService _emailService;
public async Task NotifyOrderCreatedAsync(Order order, string email)
{
await _emailService.SendAsync(email, "Order Confirmed", $"Order {order.Id} confirmed!");
}
}SRP Test: Ask These Questions
SRP测试:提出这些问题
- Can I describe what the class does without using "and"?
- Would different stakeholders want changes to this class?
- Does the class have more than 200-300 lines?
- 我能否不用“和”字来描述这个类的功能?
- 不同的利益相关者是否会想要修改这个类?
- 这个类的代码行数是否超过200-300行?
O - Open/Closed Principle (OCP)
O - 开闭原则(OCP)
Software entities should be open for extension but closed for modification.
软件实体应对扩展开放,对修改关闭。
Violation Example
反例
csharp
// BAD: Must modify class to add new discount types
public class DiscountCalculator
{
public decimal Calculate(Order order, string discountType)
{
switch (discountType)
{
case "percentage":
return order.Total * 0.1m;
case "fixed":
return 10m;
case "loyalty":
return order.Total * 0.15m;
// Every new discount requires modifying this class
default:
return 0m;
}
}
}csharp
// 不良示例:添加新折扣类型必须修改类
public class DiscountCalculator
{
public decimal Calculate(Order order, string discountType)
{
switch (discountType)
{
case "percentage":
return order.Total * 0.1m;
case "fixed":
return 10m;
case "loyalty":
return order.Total * 0.15m;
// 每新增一种折扣都需要修改此类
default:
return 0m;
}
}
}Correct Implementation
正确实现
csharp
// GOOD: Extensible without modification
public interface IDiscountStrategy
{
decimal Calculate(Order order);
}
public class PercentageDiscount : IDiscountStrategy
{
private readonly decimal _percentage;
public PercentageDiscount(decimal percentage) => _percentage = percentage;
public decimal Calculate(Order order) => order.Total * _percentage;
}
public class FixedDiscount : IDiscountStrategy
{
private readonly decimal _amount;
public FixedDiscount(decimal amount) => _amount = amount;
public decimal Calculate(Order order) => Math.Min(_amount, order.Total);
}
public class LoyaltyDiscount : IDiscountStrategy
{
private readonly ILoyaltyService _loyaltyService;
public LoyaltyDiscount(ILoyaltyService loyaltyService) => _loyaltyService = loyaltyService;
public decimal Calculate(Order order)
{
var tier = _loyaltyService.GetCustomerTier(order.CustomerId);
return tier switch
{
LoyaltyTier.Gold => order.Total * 0.15m,
LoyaltyTier.Silver => order.Total * 0.10m,
_ => 0m
};
}
}
// New discounts added without touching existing code
public class BulkDiscount : IDiscountStrategy
{
public decimal Calculate(Order order)
{
if (order.Items.Count >= 10)
return order.Total * 0.20m;
return 0m;
}
}
// Calculator is closed for modification
public class DiscountCalculator
{
public decimal Calculate(Order order, IDiscountStrategy strategy)
{
return strategy.Calculate(order);
}
}csharp
// 良好示例:无需修改即可扩展
public interface IDiscountStrategy
{
decimal Calculate(Order order);
}
public class PercentageDiscount : IDiscountStrategy
{
private readonly decimal _percentage;
public PercentageDiscount(decimal percentage) => _percentage = percentage;
public decimal Calculate(Order order) => order.Total * _percentage;
}
public class FixedDiscount : IDiscountStrategy
{
private readonly decimal _amount;
public FixedDiscount(decimal amount) => _amount = amount;
public decimal Calculate(Order order) => Math.Min(_amount, order.Total);
}
public class LoyaltyDiscount : IDiscountStrategy
{
private readonly ILoyaltyService _loyaltyService;
public LoyaltyDiscount(ILoyaltyService loyaltyService) => _loyaltyService = loyaltyService;
public decimal Calculate(Order order)
{
var tier = _loyaltyService.GetCustomerTier(order.CustomerId);
return tier switch
{
LoyaltyTier.Gold => order.Total * 0.15m,
LoyaltyTier.Silver => order.Total * 0.10m,
_ => 0m
};
}
}
// 新增折扣无需修改现有代码
public class BulkDiscount : IDiscountStrategy
{
public decimal Calculate(Order order)
{
if (order.Items.Count >= 10)
return order.Total * 0.20m;
return 0m;
}
}
// 计算器对修改关闭
public class DiscountCalculator
{
public decimal Calculate(Order order, IDiscountStrategy strategy)
{
return strategy.Calculate(order);
}
}OCP Patterns
OCP常用模式
- Strategy Pattern (as shown above)
- Template Method Pattern
- Decorator Pattern
- Plugin Architecture
- 策略模式(如上所示)
- 模板方法模式
- 装饰器模式
- 插件架构
L - Liskov Substitution Principle (LSP)
L - 里氏替换原则(LSP)
Objects of a superclass should be replaceable with objects of its subclasses without breaking the application.
基类的对象应该能够被子类的对象替换,且不会破坏应用程序的功能。
Violation Example
反例
csharp
// BAD: Square violates Rectangle's contract
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public int CalculateArea() => Width * Height;
}
public class Square : Rectangle
{
public override int Width
{
get => base.Width;
set
{
base.Width = value;
base.Height = value; // Unexpected side effect!
}
}
public override int Height
{
get => base.Height;
set
{
base.Height = value;
base.Width = value; // Unexpected side effect!
}
}
}
// This test fails for Square!
[Fact]
public void Rectangle_SetDimensions_CalculatesCorrectArea()
{
Rectangle rect = new Square(); // Substitution
rect.Width = 5;
rect.Height = 4;
Assert.Equal(20, rect.CalculateArea()); // Fails! Returns 16
}csharp
// 不良示例:Square违反了Rectangle的契约
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public int CalculateArea() => Width * Height;
}
public class Square : Rectangle
{
public override int Width
{
get => base.Width;
set
{
base.Width = value;
base.Height = value; // 意外的副作用!
}
}
public override int Height
{
get => base.Height;
set
{
base.Height = value;
base.Width = value; // 意外的副作用!
}
}
}
// 这个测试对Square会失败!
[Fact]
public void Rectangle_SetDimensions_CalculatesCorrectArea()
{
Rectangle rect = new Square(); // 替换
rect.Width = 5;
rect.Height = 4;
Assert.Equal(20, rect.CalculateArea()); // 失败!返回16
}Correct Implementation
正确实现
csharp
// GOOD: Separate abstractions
public interface IShape
{
int CalculateArea();
}
public class Rectangle : IShape
{
public int Width { get; }
public int Height { get; }
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
public int CalculateArea() => Width * Height;
}
public class Square : IShape
{
public int Side { get; }
public Square(int side) => Side = side;
public int CalculateArea() => Side * Side;
}
// Both work correctly with the abstraction
public class AreaCalculator
{
public int TotalArea(IEnumerable<IShape> shapes)
{
return shapes.Sum(s => s.CalculateArea());
}
}csharp
// 良好示例:分离抽象
public interface IShape
{
int CalculateArea();
}
public class Rectangle : IShape
{
public int Width { get; }
public int Height { get; }
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
public int CalculateArea() => Width * Height;
}
public class Square : IShape
{
public int Side { get; }
public Square(int side) => Side = side;
public int CalculateArea() => Side * Side;
}
// 两者都能通过抽象正确工作
public class AreaCalculator
{
public int TotalArea(IEnumerable<IShape> shapes)
{
return shapes.Sum(s => s.CalculateArea());
}
}LSP Rules
LSP规则
- Preconditions cannot be strengthened in subtype
- Postconditions cannot be weakened in subtype
- Invariants must be preserved in subtype
- History constraint (no unexpected state changes)
- 子类不能强化前置条件
- 子类不能弱化后置条件
- 不变量必须在子类中保留
- 历史约束(无意外状态变化)
Common LSP Violations
常见LSP违反情况
csharp
// BAD: Throwing NotSupportedException
public class ReadOnlyCollection<T> : ICollection<T>
{
public void Add(T item) => throw new NotSupportedException();
}
// BAD: Ignoring base class behavior
public class CachedRepository : Repository
{
public override void Save(Entity entity)
{
// Doesn't call base.Save() - breaks persistence!
_cache.Add(entity);
}
}csharp
// 不良示例:抛出NotSupportedException
public class ReadOnlyCollection<T> : ICollection<T>
{
public void Add(T item) => throw new NotSupportedException();
}
// 不良示例:忽略基类行为
public class CachedRepository : Repository
{
public override void Save(Entity entity)
{
// 未调用base.Save() - 破坏持久化!
_cache.Add(entity);
}
}I - Interface Segregation Principle (ISP)
I - 接口隔离原则(ISP)
Clients should not be forced to depend on interfaces they do not use.
客户端不应被迫依赖它们不需要的接口。
Violation Example
反例
csharp
// BAD: Fat interface
public interface IWorker
{
void Work();
void Eat();
void Sleep();
void AttendMeeting();
void WriteCode();
void ManageTeam();
}
// Robot can't eat or sleep!
public class Robot : IWorker
{
public void Work() { /* OK */ }
public void Eat() => throw new NotSupportedException();
public void Sleep() => throw new NotSupportedException();
public void AttendMeeting() => throw new NotSupportedException();
public void WriteCode() { /* OK */ }
public void ManageTeam() => throw new NotSupportedException();
}csharp
// 不良示例:臃肿接口
public interface IWorker
{
void Work();
void Eat();
void Sleep();
void AttendMeeting();
void WriteCode();
void ManageTeam();
}
// 机器人无法进食或睡眠!
public class Robot : IWorker
{
public void Work() { /* 正常 */ }
public void Eat() => throw new NotSupportedException();
public void Sleep() => throw new NotSupportedException();
public void AttendMeeting() => throw new NotSupportedException();
public void WriteCode() { /* 正常 */ }
public void ManageTeam() => throw new NotSupportedException();
}Correct Implementation
正确实现
csharp
// GOOD: Segregated interfaces
public interface IWorkable
{
void Work();
}
public interface IFeedable
{
void Eat();
}
public interface ISleepable
{
void Sleep();
}
public interface IMeetingAttendee
{
void AttendMeeting();
}
public interface IDeveloper : IWorkable
{
void WriteCode();
}
public interface IManager : IWorkable, IMeetingAttendee
{
void ManageTeam();
}
// Clean implementations
public class HumanDeveloper : IDeveloper, IFeedable, ISleepable
{
public void Work() { }
public void WriteCode() { }
public void Eat() { }
public void Sleep() { }
}
public class Robot : IDeveloper
{
public void Work() { }
public void WriteCode() { }
// No forced empty implementations!
}csharp
// 良好示例:隔离的接口
public interface IWorkable
{
void Work();
}
public interface IFeedable
{
void Eat();
}
public interface ISleepable
{
void Sleep();
}
public interface IMeetingAttendee
{
void AttendMeeting();
}
public interface IDeveloper : IWorkable
{
void WriteCode();
}
public interface IManager : IWorkable, IMeetingAttendee
{
void ManageTeam();
}
// 简洁的实现
public class HumanDeveloper : IDeveloper, IFeedable, ISleepable
{
public void Work() { }
public void WriteCode() { }
public void Eat() { }
public void Sleep() { }
}
public class Robot : IDeveloper
{
public void Work() { }
public void WriteCode() { }
// 无需强制实现空方法!
}Repository ISP Example
仓库模式的ISP示例
csharp
// BAD: Monolithic repository
public interface IRepository<T>
{
T GetById(int id);
IEnumerable<T> GetAll();
void Add(T entity);
void Update(T entity);
void Delete(T entity);
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
void BulkInsert(IEnumerable<T> entities);
void ExecuteRawSql(string sql);
}
// GOOD: Segregated repositories
public interface IReadRepository<T>
{
T? GetById(int id);
IEnumerable<T> GetAll();
}
public interface IWriteRepository<T>
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
public interface IQueryRepository<T>
{
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
// Compose as needed
public interface IOrderRepository : IReadRepository<Order>, IWriteRepository<Order> { }
public interface IReportRepository : IReadRepository<Report>, IQueryRepository<Report> { }csharp
// 不良示例:单体仓库接口
public interface IRepository<T>
{
T GetById(int id);
IEnumerable<T> GetAll();
void Add(T entity);
void Update(T entity);
void Delete(T entity);
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
void BulkInsert(IEnumerable<T> entities);
void ExecuteRawSql(string sql);
}
// 良好示例:隔离的仓库接口
public interface IReadRepository<T>
{
T? GetById(int id);
IEnumerable<T> GetAll();
}
public interface IWriteRepository<T>
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
public interface IQueryRepository<T>
{
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
}
// 根据需要组合
public interface IOrderRepository : IReadRepository<Order>, IWriteRepository<Order> { }
public interface IReportRepository : IReadRepository<Report>, IQueryRepository<Report> { }D - Dependency Inversion Principle (DIP)
D - 依赖倒置原则(DIP)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
高层模块不应依赖低层模块,两者都应依赖抽象。
Violation Example
反例
csharp
// BAD: High-level depends on low-level
public class OrderService
{
private readonly SqlOrderRepository _repository; // Concrete!
private readonly SmtpEmailSender _emailSender; // Concrete!
public OrderService()
{
_repository = new SqlOrderRepository("connection-string");
_emailSender = new SmtpEmailSender("smtp.server.com");
}
public void CreateOrder(Order order)
{
_repository.Save(order);
_emailSender.Send(order.CustomerEmail, "Order Created");
}
}csharp
// 不良示例:高层依赖低层具体实现
public class OrderService
{
private readonly SqlOrderRepository _repository; // 具体类!
private readonly SmtpEmailSender _emailSender; // 具体类!
public OrderService()
{
_repository = new SqlOrderRepository("connection-string");
_emailSender = new SmtpEmailSender("smtp.server.com");
}
public void CreateOrder(Order order)
{
_repository.Save(order);
_emailSender.Send(order.CustomerEmail, "Order Created");
}
}Correct Implementation
正确实现
csharp
// GOOD: Depend on abstractions
public interface IOrderRepository
{
Task SaveAsync(Order order);
Task<Order?> GetByIdAsync(Guid id);
}
public interface INotificationService
{
Task SendAsync(string recipient, string subject, string message);
}
public class OrderService
{
private readonly IOrderRepository _repository;
private readonly INotificationService _notificationService;
// Dependencies injected via constructor
public OrderService(
IOrderRepository repository,
INotificationService notificationService)
{
_repository = repository;
_notificationService = notificationService;
}
public async Task CreateOrderAsync(Order order)
{
await _repository.SaveAsync(order);
await _notificationService.SendAsync(
order.CustomerEmail,
"Order Created",
$"Your order {order.Id} has been created.");
}
}
// Low-level modules implement abstractions
public class SqlOrderRepository : IOrderRepository
{
private readonly DbContext _context;
public SqlOrderRepository(DbContext context) => _context = context;
public async Task SaveAsync(Order order)
{
_context.Orders.Add(order);
await _context.SaveChangesAsync();
}
public async Task<Order?> GetByIdAsync(Guid id)
{
return await _context.Orders.FindAsync(id);
}
}
public class EmailNotificationService : INotificationService
{
private readonly IEmailClient _emailClient;
public EmailNotificationService(IEmailClient emailClient) => _emailClient = emailClient;
public async Task SendAsync(string recipient, string subject, string message)
{
await _emailClient.SendEmailAsync(recipient, subject, message);
}
}
// Registration in DI container
services.AddScoped<IOrderRepository, SqlOrderRepository>();
services.AddScoped<INotificationService, EmailNotificationService>();
services.AddScoped<OrderService>();csharp
// 良好示例:依赖抽象
public interface IOrderRepository
{
Task SaveAsync(Order order);
Task<Order?> GetByIdAsync(Guid id);
}
public interface INotificationService
{
Task SendAsync(string recipient, string subject, string message);
}
public class OrderService
{
private readonly IOrderRepository _repository;
private readonly INotificationService _notificationService;
// 通过构造函数注入依赖
public OrderService(
IOrderRepository repository,
INotificationService notificationService)
{
_repository = repository;
_notificationService = notificationService;
}
public async Task CreateOrderAsync(Order order)
{
await _repository.SaveAsync(order);
await _notificationService.SendAsync(
order.CustomerEmail,
"Order Created",
$"Your order {order.Id} has been created.");
}
}
// 低层模块实现抽象
public class SqlOrderRepository : IOrderRepository
{
private readonly DbContext _context;
public SqlOrderRepository(DbContext context) => _context = context;
public async Task SaveAsync(Order order)
{
_context.Orders.Add(order);
await _context.SaveChangesAsync();
}
public async Task<Order?> GetByIdAsync(Guid id)
{
return await _context.Orders.FindAsync(id);
}
}
public class EmailNotificationService : INotificationService
{
private readonly IEmailClient _emailClient;
public EmailNotificationService(IEmailClient emailClient) => _emailClient = emailClient;
public async Task SendAsync(string recipient, string subject, string message)
{
await _emailClient.SendEmailAsync(recipient, subject, message);
}
}
// 在DI容器中注册
services.AddScoped<IOrderRepository, SqlOrderRepository>();
services.AddScoped<INotificationService, EmailNotificationService>();
services.AddScoped<OrderService>();DIP Benefits
DIP优势
- Testability: Mock dependencies easily
- Flexibility: Swap implementations without changing consumers
- Maintainability: Changes isolated to implementations
- Parallel development: Teams work on interfaces
- 可测试性:轻松模拟依赖项
- 灵活性:无需修改消费者即可替换实现
- 可维护性:变更被隔离在实现层
- 并行开发:团队可基于接口并行工作
Quick Reference
快速参考
| Principle | Violation Sign | Fix |
|---|---|---|
| SRP | Class has multiple reasons to change | Extract classes by responsibility |
| OCP | Adding features requires modifying existing code | Use abstractions and composition |
| LSP | Subclass can't substitute base class | Fix inheritance or use composition |
| ISP | Implementations throw NotSupported | Split large interfaces |
| DIP | High-level creates low-level instances | Inject dependencies via interfaces |
See examples.md for more comprehensive examples.
| 原则 | 违反迹象 | 修复方案 |
|---|---|---|
| SRP | 类有多个修改理由 | 按职责提取类 |
| OCP | 添加功能需要修改现有代码 | 使用抽象和组合 |
| LSP | 子类无法替换基类 | 修复继承关系或使用组合 |
| ISP | 实现类抛出NotSupportedException | 拆分大型接口 |
| DIP | 高层模块创建低层模块实例 | 通过接口注入依赖 |
更多完整示例请查看examples.md。