21 KiB
21 KiB
1.5 OOP规范
1. 类的职责划分
1.1 单一职责原则
// ❌ 不建议:一个类承担多个职责
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 类的大小控制
// - 方法数量:建议不超过 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 字段私有化
// ❌ 不建议:公开字段
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 属性设计
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 对象不变性
// ✅ 不可变对象(线程安全)
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 何时使用继承
// ✅ 正确使用继承
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 继承层次控制
// ✅ 继承深度建议不超过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 虚方法使用规范
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 使用组合的场景
// ❌ 错误:使用继承实现不同功能组合
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 策略模式代替继承
// ✅ 使用策略模式提供不同行为
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 接口命名与定义
// ✅ 接口命名以 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 接口隔离
// ❌ 不建议:臃肿的接口
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 显式接口实现
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 接口
// ✅ 使用抽象类:有共同实现逻辑
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 抽象类设计要点
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
// ✅ 防止被继承(性能优化、设计意图)
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 访问级别选择
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 最小权限原则
// ✅ 建议:默认使用最小访问权限
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) { }
}