799 lines
21 KiB
Markdown
799 lines
21 KiB
Markdown
# 1.5 OOP规范
|
||
|
||
---
|
||
|
||
## 1. 类的职责划分
|
||
### 1.1 单一职责原则
|
||
```csharp
|
||
// ❌ 不建议:一个类承担多个职责
|
||
public class User
|
||
{
|
||
public int Id { get; set; }
|
||
public string Name { get; set; }
|
||
public string Email { get; set; }
|
||
// 数据访问职责
|
||
public void SaveToDatabase() { }
|
||
// 邮件发送职责
|
||
public void SendWelcomeEmail() { }
|
||
// 日志记录职责
|
||
public void LogUserAction() { }
|
||
// 数据验证职责
|
||
public bool ValidateEmail() { }
|
||
}
|
||
// ✅ 建议:职责分离
|
||
public class User
|
||
{
|
||
public int Id { get; set; }
|
||
public string Name { get; set; }
|
||
public string Email { get; set; }
|
||
}
|
||
public class UserRepository
|
||
{
|
||
public async Task SaveAsync(User user)
|
||
{
|
||
// 数据访问逻辑
|
||
}
|
||
}
|
||
public class UserEmailService
|
||
{
|
||
public async Task SendWelcomeEmailAsync(User user)
|
||
{
|
||
// 邮件发送逻辑
|
||
}
|
||
}
|
||
public class UserValidator
|
||
{
|
||
public bool IsValidEmail(string email)
|
||
{
|
||
// 验证逻辑
|
||
}
|
||
}
|
||
```
|
||
### 1.2 类的大小控制
|
||
```csharp
|
||
// - 方法数量:建议不超过 20 个
|
||
// - 代码行数:建议不超过 300 行
|
||
// - 依赖数量:建议不超过 5 个
|
||
public class OrderService
|
||
{
|
||
// 依赖注入(建议最多5个依赖)
|
||
private readonly IOrderRepository _orderRepository;
|
||
private readonly IProductService _productService;
|
||
private readonly IEmailService _emailService;
|
||
private readonly ILogger<OrderService> _logger;
|
||
public OrderService(
|
||
IOrderRepository orderRepository,
|
||
IProductService productService,
|
||
IEmailService emailService,
|
||
ILogger<OrderService> logger)
|
||
{
|
||
_orderRepository = orderRepository;
|
||
_productService = productService;
|
||
_emailService = emailService;
|
||
_logger = logger;
|
||
}
|
||
// 核心业务方法
|
||
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
|
||
{
|
||
// 方法体不超过30行
|
||
}
|
||
}
|
||
// ❌ 如果类过大,考虑拆分
|
||
// 例如:将订单创建、订单查询、订单取消拆分为不同的服务类
|
||
public class OrderCreationService { }
|
||
public class OrderQueryService { }
|
||
public class OrderCancellationService
|
||
```
|
||
## 2. 封装原则
|
||
### 2.1 字段私有化
|
||
```csharp
|
||
// ❌ 不建议:公开字段
|
||
public class BankAccount
|
||
{
|
||
public decimal Balance; // 可被外部直接修改
|
||
}
|
||
// ✅ 建议:私有字段 + 公共属性
|
||
public class BankAccount
|
||
{
|
||
private decimal _balance;
|
||
public decimal Balance
|
||
{
|
||
get => _balance;
|
||
private set => _balance = value; // 只能内部修改
|
||
}
|
||
// 通过方法控制状态变化
|
||
public void Deposit(decimal amount)
|
||
{
|
||
if (amount <= 0)
|
||
{
|
||
throw new ArgumentException("存款金额必须大于0");
|
||
}
|
||
_balance += amount;
|
||
}
|
||
public void Withdraw(decimal amount)
|
||
{
|
||
if (amount <= 0)
|
||
{
|
||
throw new ArgumentException("取款金额必须大于0");
|
||
}
|
||
if (amount > _balance)
|
||
{
|
||
throw new InvalidOperationException("余额不足");
|
||
}
|
||
_balance -= amount;
|
||
}
|
||
}
|
||
```
|
||
### 2.2 属性设计
|
||
```csharp
|
||
public class Product
|
||
{
|
||
// ✅ 自动属性(简单场景)
|
||
public int Id { get; set; }
|
||
public string Name { get; set; }
|
||
// ✅ 只读属性(外部只能读取)
|
||
public DateTime CreateTime { get; private set; }
|
||
// ✅ 计算属性(不存储值)
|
||
public decimal TotalPrice => Price * Quantity;
|
||
// ✅ 带验证的属性
|
||
private decimal _price;
|
||
public decimal Price
|
||
{
|
||
get => _price;
|
||
set
|
||
{
|
||
if (value < 0)
|
||
{
|
||
throw new ArgumentException("价格不能为负数");
|
||
}
|
||
_price = value;
|
||
}
|
||
}
|
||
// ✅ 延迟初始化属性
|
||
private List<Review> _reviews;
|
||
public List<Review> Reviews => _reviews ??= new List<Review>();
|
||
// ✅ init 访问器(只能在构造时设置)
|
||
public string Code { get; init; }
|
||
// ✅ required 修饰符(C# 11+)
|
||
public required string Category { get; init; }
|
||
}
|
||
// 使用示例
|
||
var product = new Product
|
||
{
|
||
Code = "P001",
|
||
Category = "电子产品", // 必须设置
|
||
Price = 999.99m
|
||
};
|
||
// product.Code = "P002"; // 编译错误,init 属性不可修改
|
||
```
|
||
### 2.3 对象不变性
|
||
```csharp
|
||
// ✅ 不可变对象(线程安全)
|
||
public class Money
|
||
{
|
||
public decimal Amount { get; }
|
||
public string Currency { get; }
|
||
public Money(decimal amount, string currency)
|
||
{
|
||
if (amount < 0)
|
||
{
|
||
throw new ArgumentException("金额不能为负数");
|
||
}
|
||
Amount = amount;
|
||
Currency = currency ?? throw new ArgumentNullException(nameof(currency));
|
||
}
|
||
// 操作返回新对象,而不修改当前对象
|
||
public Money Add(Money other)
|
||
{
|
||
if (Currency != other.Currency)
|
||
{
|
||
throw new InvalidOperationException("货币类型不同");
|
||
}
|
||
return new Money(Amount + other.Amount, Currency);
|
||
}
|
||
public Money Multiply(decimal factor)
|
||
{
|
||
return new Money(Amount * factor, Currency);
|
||
}
|
||
}
|
||
// ✅ 使用 record 创建不可变对象
|
||
public record Address(string Street, string City, string ZipCode);
|
||
// 使用
|
||
var address = new Address("中山路100号", "上海", "200000");
|
||
// address.Street = "新地址"; // 编译错误
|
||
// 创建副本并修改
|
||
var newAddress = address with { Street = "南京路200号" };
|
||
```
|
||
## 3. 继承使用原则
|
||
### 3.1 何时使用继承
|
||
```csharp
|
||
// ✅ 正确使用继承
|
||
public abstract class Animal
|
||
{
|
||
public string Name { get; set; }
|
||
public abstract void MakeSound();
|
||
public virtual void Eat()
|
||
{
|
||
Console.WriteLine($"{Name} is eating");
|
||
}
|
||
}
|
||
public class Dog : Animal
|
||
{
|
||
public override void MakeSound()
|
||
{
|
||
Console.WriteLine("Woof!");
|
||
}
|
||
}
|
||
public class Cat : Animal
|
||
{
|
||
public override void MakeSound()
|
||
{
|
||
Console.WriteLine("Meow!");
|
||
}
|
||
public override void Eat()
|
||
{
|
||
base.Eat(); // 调用基类实现
|
||
Console.WriteLine("Cat loves fish");
|
||
}
|
||
}
|
||
// ❌ 错误使用继承:仅为复用代码
|
||
public class Stack : List<int> // 不应该继承 List
|
||
{
|
||
// Stack 不是一个 List
|
||
}
|
||
// ✅ 正确:使用组合
|
||
public class Stack
|
||
{
|
||
private readonly List<int> _items = new();
|
||
public void Push(int item) => _items.Add(item);
|
||
public int Pop()
|
||
{
|
||
var item = _items[^1];
|
||
_items.RemoveAt(_items.Count - 1);
|
||
return item;
|
||
}
|
||
}
|
||
```
|
||
### 3.2 继承层次控制
|
||
```csharp
|
||
// ✅ 继承深度建议不超过3层
|
||
// Level 1
|
||
public abstract class Entity
|
||
{
|
||
public int Id { get; set; }
|
||
}
|
||
// Level 2
|
||
public abstract class AuditableEntity : Entity
|
||
{
|
||
public DateTime CreateTime { get; set; }
|
||
public DateTime? UpdateTime { get; set; }
|
||
}
|
||
// Level 3
|
||
public class Product : AuditableEntity
|
||
{
|
||
public string Name { get; set; }
|
||
public decimal Price { get; set; }
|
||
}
|
||
// ❌ 避免更深的继承层次
|
||
// Level 4 - 过深
|
||
public class SpecialProduct : Product { } // 考虑重新设计
|
||
```
|
||
### 3.3 虚方法使用规范
|
||
```csharp
|
||
public abstract class PaymentProcessor
|
||
{
|
||
// ✅ 模板方法模式
|
||
public async Task<PaymentResult> ProcessPaymentAsync(PaymentRequest request)
|
||
{
|
||
// 1. 验证(子类可重写)
|
||
ValidateRequest(request);
|
||
// 2. 预处理(子类可重写)
|
||
await PreProcessAsync(request);
|
||
// 3. 核心处理(子类必须实现)
|
||
var result = await ExecutePaymentAsync(request);
|
||
// 4. 后处理(子类可重写)
|
||
await PostProcessAsync(result);
|
||
return result;
|
||
}
|
||
// 虚方法(可选重写)
|
||
protected virtual void ValidateRequest(PaymentRequest request)
|
||
{
|
||
if (request.Amount <= 0)
|
||
{
|
||
throw new ArgumentException("支付金额必须大于0");
|
||
}
|
||
}
|
||
protected virtual Task PreProcessAsync(PaymentRequest request)
|
||
{
|
||
return Task.CompletedTask;
|
||
}
|
||
// 抽象方法(必须实现)
|
||
protected abstract Task<PaymentResult> ExecutePaymentAsync(PaymentRequest request);
|
||
protected virtual Task PostProcessAsync(PaymentResult result)
|
||
{
|
||
return Task.CompletedTask;
|
||
}
|
||
}
|
||
// 具体实现
|
||
public class AlipayProcessor : PaymentProcessor
|
||
{
|
||
protected override async Task<PaymentResult> ExecutePaymentAsync(PaymentRequest request)
|
||
{
|
||
// 支付宝支付逻辑
|
||
return new PaymentResult { Success = true };
|
||
}
|
||
protected override async Task PostProcessAsync(PaymentResult result)
|
||
{
|
||
// 发送支付通知
|
||
await base.PostProcessAsync(result);
|
||
}
|
||
}
|
||
```
|
||
## 4. 组合优于继承
|
||
### 4.1 使用组合的场景
|
||
```csharp
|
||
// ❌ 错误:使用继承实现不同功能组合
|
||
public class FlyingSwimmingAnimal : Animal { } // 会飞会游泳的动物?
|
||
// ✅ 正确:使用组合和接口
|
||
public interface IFlyable
|
||
{
|
||
void Fly();
|
||
}
|
||
public interface ISwimmable
|
||
{
|
||
void Swim();
|
||
}
|
||
public class Duck : Animal, IFlyable, ISwimmable
|
||
{
|
||
private readonly FlyingAbility _flyingAbility = new();
|
||
private readonly SwimmingAbility _swimmingAbility = new();
|
||
public void Fly() => _flyingAbility.Fly();
|
||
public void Swim() => _swimmingAbility.Swim();
|
||
public override void MakeSound()
|
||
{
|
||
Console.WriteLine("Quack!");
|
||
}
|
||
}
|
||
public class FlyingAbility
|
||
{
|
||
public void Fly()
|
||
{
|
||
Console.WriteLine("Flying in the sky");
|
||
}
|
||
}
|
||
public class SwimmingAbility
|
||
{
|
||
public void Swim()
|
||
{
|
||
Console.WriteLine("Swimming in the water");
|
||
}
|
||
}
|
||
```
|
||
### 4.2 策略模式代替继承
|
||
```csharp
|
||
// ✅ 使用策略模式提供不同行为
|
||
public interface IShippingStrategy
|
||
{
|
||
decimal CalculateCost(decimal weight, decimal distance);
|
||
}
|
||
public class StandardShipping : IShippingStrategy
|
||
{
|
||
public decimal CalculateCost(decimal weight, decimal distance)
|
||
{
|
||
return weight * 0.5m + distance * 0.1m;
|
||
}
|
||
}
|
||
public class ExpressShipping : IShippingStrategy
|
||
{
|
||
public decimal CalculateCost(decimal weight, decimal distance)
|
||
{
|
||
return weight * 1.0m + distance * 0.2m + 20m;
|
||
}
|
||
}
|
||
public class Order
|
||
{
|
||
private IShippingStrategy _shippingStrategy;
|
||
public void SetShippingStrategy(IShippingStrategy strategy)
|
||
{
|
||
_shippingStrategy = strategy ?? throw new ArgumentNullException(nameof(strategy));
|
||
}
|
||
public decimal CalculateShippingCost(decimal weight, decimal distance)
|
||
{
|
||
if (_shippingStrategy == null)
|
||
{
|
||
throw new InvalidOperationException("运输策略未设置");
|
||
}
|
||
return _shippingStrategy.CalculateCost(weight, distance);
|
||
}
|
||
}
|
||
```
|
||
## 5. 接口设计原则
|
||
### 5.1 接口命名与定义
|
||
```csharp
|
||
// ✅ 接口命名以 I 开头
|
||
public interface ICustomerRepository
|
||
{
|
||
Task<Customer> GetByIdAsync(int id);
|
||
Task<IEnumerable<Customer>> GetAllAsync();
|
||
Task<Customer> AddAsync(Customer customer);
|
||
Task UpdateAsync(Customer customer);
|
||
Task DeleteAsync(int id);
|
||
}
|
||
// ✅ 能力接口(形容词)
|
||
public interface IDisposable
|
||
{
|
||
void Dispose();
|
||
}
|
||
public interface IComparable<T>
|
||
{
|
||
int CompareTo(T other);
|
||
}
|
||
// ✅ 服务接口(名词)
|
||
public interface IEmailService
|
||
{
|
||
Task SendAsync(string to, string subject, string body);
|
||
}
|
||
public interface ILogger<T>
|
||
{
|
||
void LogInformation(string message);
|
||
void LogError(Exception ex, string message);
|
||
}
|
||
```
|
||
### 5.2 接口隔离
|
||
```csharp
|
||
// ❌ 不建议:臃肿的接口
|
||
public interface IRepository
|
||
{
|
||
// CRUD 操作
|
||
void Add();
|
||
void Update();
|
||
void Delete();
|
||
void Get();
|
||
// 批量操作
|
||
void BulkAdd();
|
||
void BulkUpdate();
|
||
void BulkDelete();
|
||
// 搜索功能
|
||
void Search();
|
||
void AdvancedSearch();
|
||
// 导出功能
|
||
void ExportToExcel();
|
||
void ExportToPdf();
|
||
}
|
||
// ✅ 建议:接口隔离
|
||
public interface IReadRepository<T>
|
||
{
|
||
Task<T> GetByIdAsync(int id);
|
||
Task<IEnumerable<T>> GetAllAsync();
|
||
}
|
||
public interface IWriteRepository<T>
|
||
{
|
||
Task<T> AddAsync(T entity);
|
||
Task UpdateAsync(T entity);
|
||
Task DeleteAsync(int id);
|
||
}
|
||
public interface IBulkRepository<T>
|
||
{
|
||
Task BulkAddAsync(IEnumerable<T> entities);
|
||
Task BulkUpdateAsync(IEnumerable<T> entities);
|
||
}
|
||
public interface ISearchableRepository<T>
|
||
{
|
||
Task<IEnumerable<T>> SearchAsync(SearchCriteria criteria);
|
||
}
|
||
// 组合使用
|
||
public interface ICustomerRepository : IReadRepository<Customer>,
|
||
IWriteRepository<Customer>,
|
||
ISearchableRepository<Customer>
|
||
{
|
||
// 特定于 Customer 的方法
|
||
Task<Customer> GetByEmailAsync(string email);
|
||
}
|
||
```
|
||
### 5.3 显式接口实现
|
||
```csharp
|
||
public interface IAnimal
|
||
{
|
||
void Move();
|
||
}
|
||
public interface IRobot
|
||
{
|
||
void Move();
|
||
}
|
||
// ✅ 显式接口实现解决方法冲突
|
||
public class RobotDog : IAnimal, IRobot
|
||
{
|
||
// 隐式实现(默认)
|
||
public void Move()
|
||
{
|
||
Console.WriteLine("RobotDog moving");
|
||
}
|
||
// 显式实现 IAnimal
|
||
void IAnimal.Move()
|
||
{
|
||
Console.WriteLine("Animal walking");
|
||
}
|
||
// 显式实现 IRobot
|
||
void IRobot.Move()
|
||
{
|
||
Console.WriteLine("Robot moving mechanically");
|
||
}
|
||
}
|
||
// 使用
|
||
var robotDog = new RobotDog();
|
||
robotDog.Move(); // "RobotDog moving"
|
||
((IAnimal)robotDog).Move(); // "Animal walking"
|
||
((IRobot)robotDog).Move(); // "Robot moving mechanically"
|
||
```
|
||
## 6. 抽象类使用场景
|
||
### 6.1 抽象类 vs 接口
|
||
```csharp
|
||
// ✅ 使用抽象类:有共同实现逻辑
|
||
public abstract class Document
|
||
{
|
||
// 公共属性
|
||
public string Title { get; set; }
|
||
public DateTime CreateTime { get; set; }
|
||
// 公共方法实现
|
||
public void Save()
|
||
{
|
||
ValidateBeforeSave();
|
||
PerformSave();
|
||
LogSave();
|
||
}
|
||
// 模板方法
|
||
protected virtual void ValidateBeforeSave()
|
||
{
|
||
if (string.IsNullOrWhiteSpace(Title))
|
||
{
|
||
throw new ValidationException("标题不能为空");
|
||
}
|
||
}
|
||
// 抽象方法(强制子类实现)
|
||
protected abstract void PerformSave();
|
||
// 虚方法(可选重写)
|
||
protected virtual void LogSave()
|
||
{
|
||
Console.WriteLine($"Document '{Title}' saved at {DateTime.Now}");
|
||
}
|
||
}
|
||
public class PdfDocument : Document
|
||
{
|
||
protected override void PerformSave()
|
||
{
|
||
// PDF 特定的保存逻辑
|
||
Console.WriteLine("Saving as PDF");
|
||
}
|
||
}
|
||
public class WordDocument : Document
|
||
{
|
||
protected override void PerformSave()
|
||
{
|
||
// Word 特定的保存逻辑
|
||
Console.WriteLine("Saving as Word document");
|
||
}
|
||
protected override void ValidateBeforeSave()
|
||
{
|
||
base.ValidateBeforeSave();
|
||
// 额外的验证逻辑
|
||
}
|
||
}
|
||
// ✅ 使用接口:定义契约,无共同实现
|
||
public interface INotificationSender
|
||
{
|
||
Task SendAsync(string recipient, string message);
|
||
}
|
||
public class EmailSender : INotificationSender
|
||
{
|
||
public async Task SendAsync(string recipient, string message)
|
||
{
|
||
// 邮件发送实现
|
||
}
|
||
}
|
||
public class SmsSender : INotificationSender
|
||
{
|
||
public async Task SendAsync(string recipient, string message)
|
||
{
|
||
// 短信发送实现
|
||
}
|
||
}
|
||
```
|
||
### 6.2 抽象类设计要点
|
||
```csharp
|
||
public abstract class BaseEntity
|
||
{
|
||
// ✅ 抽象类可以有构造函数
|
||
protected BaseEntity()
|
||
{
|
||
CreateTime = DateTime.UtcNow;
|
||
Id = Guid.NewGuid();
|
||
}
|
||
// ✅ 可以有字段
|
||
private readonly List<DomainEvent> _domainEvents = new();
|
||
// 公共属性
|
||
public Guid Id { get; private set; }
|
||
public DateTime CreateTime { get; private set; }
|
||
public DateTime? UpdateTime { get; protected set; }
|
||
// ✅ 受保护的方法供子类使用
|
||
protected void AddDomainEvent(DomainEvent domainEvent)
|
||
{
|
||
_domainEvents.Add(domainEvent);
|
||
}
|
||
protected void MarkAsUpdated()
|
||
{
|
||
UpdateTime = DateTime.UtcNow;
|
||
}
|
||
// 抽象方法
|
||
public abstract void Validate();
|
||
}
|
||
public class Customer : BaseEntity
|
||
{
|
||
public string Name { get; set; }
|
||
public string Email { get; set; }
|
||
public override void Validate()
|
||
{
|
||
if (string.IsNullOrWhiteSpace(Name))
|
||
{
|
||
throw new ValidationException("客户名称不能为空");
|
||
}
|
||
if (string.IsNullOrWhiteSpace(Email))
|
||
{
|
||
throw new ValidationException("邮箱不能为空");
|
||
}
|
||
}
|
||
public void UpdateEmail(string newEmail)
|
||
{
|
||
Email = newEmail;
|
||
MarkAsUpdated(); // 使用基类方法
|
||
AddDomainEvent(new CustomerEmailChangedEvent(Id, newEmail));
|
||
}
|
||
}
|
||
```
|
||
## 7. 密封类使用
|
||
### 7.1 何时使用 `sealed`
|
||
```csharp
|
||
// ✅ 防止被继承(性能优化、设计意图)
|
||
public sealed class ConfigurationManager
|
||
{
|
||
private readonly Dictionary<string, string> _settings = new();
|
||
public string GetSetting(string key)
|
||
{
|
||
return _settings.TryGetValue(key, out var value) ? value : null;
|
||
}
|
||
}
|
||
// ❌ 无法继承
|
||
// public class CustomConfigManager : ConfigurationManager { } // 编译错误
|
||
// ✅ 工具类密封
|
||
public sealed class StringHelper
|
||
{
|
||
private StringHelper() { } // 私有构造防止实例化
|
||
public static string Truncate(string value, int maxLength)
|
||
{
|
||
if (string.IsNullOrEmpty(value) || value.Length <= maxLength)
|
||
{
|
||
return value;
|
||
}
|
||
return value.Substring(0, maxLength) + "...";
|
||
}
|
||
}
|
||
// ✅ 密封重写方法(防止进一步重写)
|
||
public class BaseProcessor
|
||
{
|
||
public virtual void Process()
|
||
{
|
||
Console.WriteLine("Base processing");
|
||
}
|
||
}
|
||
public class DerivedProcessor : BaseProcessor
|
||
{
|
||
// 密封此方法,子类不能再重写
|
||
public sealed override void Process()
|
||
{
|
||
Console.WriteLine("Derived processing");
|
||
base.Process();
|
||
}
|
||
}
|
||
public class FurtherDerived : DerivedProcessor
|
||
{
|
||
// ❌ 编译错误:不能重写密封方法
|
||
// public override void Process() { }
|
||
}
|
||
```
|
||
## 8. 访问修饰符使用规范
|
||
### 8.1 访问级别选择
|
||
```csharp
|
||
public class Product
|
||
{
|
||
// ✅ private - 只在类内部使用
|
||
private decimal _costPrice;
|
||
private List<PriceHistory> _priceHistory = new();
|
||
// ✅ private protected - 仅当前类和派生类访问(同一程序集)
|
||
private protected void RecordPriceChange(decimal oldPrice, decimal newPrice)
|
||
{
|
||
_priceHistory.Add(new PriceHistory(oldPrice, newPrice));
|
||
}
|
||
// ✅ protected - 当前类和派生类可访问
|
||
protected decimal CostPrice => _costPrice;
|
||
// ✅ internal - 同一程序集内可访问
|
||
internal void SetCostPrice(decimal cost)
|
||
{
|
||
_costPrice = cost;
|
||
}
|
||
// ✅ protected internal - 同一程序集或派生类
|
||
protected internal decimal CalculateMargin()
|
||
{
|
||
return Price - _costPrice;
|
||
}
|
||
// ✅ public - 所有地方可访问
|
||
public decimal Price { get; set; }
|
||
public string Name { get; set; }
|
||
public decimal GetProfitMargin()
|
||
{
|
||
return (Price - _costPrice) / Price * 100;
|
||
}
|
||
}
|
||
// 访问修饰符决策树:
|
||
// 1. 只在当前类使用? -> private
|
||
// 2. 需要子类访问? -> protected
|
||
// 3. 同一程序集内使用? -> internal
|
||
// 4. 需要外部调用? -> public
|
||
// 5. 同程序集或子类? -> protected internal
|
||
// 6. 仅同程序集的子类? -> private protected
|
||
```
|
||
### 8.2 最小权限原则
|
||
```csharp
|
||
// ✅ 建议:默认使用最小访问权限
|
||
public class OrderProcessor
|
||
{
|
||
// 私有字段
|
||
private readonly IOrderRepository _repository;
|
||
private readonly ILogger _logger;
|
||
|
||
// 公共构造函数
|
||
public OrderProcessor(IOrderRepository repository, ILogger logger)
|
||
{
|
||
_repository = repository;
|
||
_logger = logger;
|
||
}
|
||
|
||
// 公共方法(对外API)
|
||
public async Task<Order> ProcessOrderAsync(int orderId)
|
||
{
|
||
var order = await GetOrderAsync(orderId);
|
||
ValidateOrder(order);
|
||
await SaveOrderAsync(order);
|
||
return order;
|
||
}
|
||
|
||
// 私有方法(内部实现细节)
|
||
private async Task<Order> GetOrderAsync(int orderId)
|
||
{
|
||
return await _repository.GetByIdAsync(orderId);
|
||
}
|
||
|
||
private void ValidateOrder(Order order)
|
||
{
|
||
if (order == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(order));
|
||
}
|
||
}
|
||
|
||
private async Task SaveOrderAsync(Order order)
|
||
{
|
||
await _repository.UpdateAsync(order);
|
||
_logger.LogInformation("Order {OrderId} saved", order.Id);
|
||
}
|
||
}
|
||
|
||
// ❌ 不建议:不必要的公开
|
||
public class BadOrderProcessor
|
||
{
|
||
// 不应该公开
|
||
public IOrderRepository Repository { get; set; }
|
||
|
||
// 不应该公开内部实现
|
||
public void ValidateOrder(Order order) { }
|
||
public async Task SaveOrderAsync(Order order) { }
|
||
}
|
||
``` |