偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

.NET 10 + DDD 領(lǐng)域驗證實戰(zhàn):構(gòu)建堅不可摧的領(lǐng)域模型核心法則

開發(fā) 前端
在 .NET 10 中,結(jié)合整潔架構(gòu)和 DDD 的領(lǐng)域驗證為構(gòu)建可維護、業(yè)務(wù)導(dǎo)向的應(yīng)用程序提供了堅實的基礎(chǔ)。通過在領(lǐng)域?qū)邮褂檬匦l(wèi)子句和結(jié)果模式等適當(dāng)模式實施驗證,同時保持清晰的關(guān)注點分離,您可以創(chuàng)建既技術(shù)上合理又與業(yè)務(wù)需求保持一致的系統(tǒng)。

驗證(Domain Validation)是在 .NET 10 中使用整潔架構(gòu)(Clean Architecture)和領(lǐng)域驅(qū)動設(shè)計(Domain-Driven Design, DDD)原則構(gòu)建健壯、可維護應(yīng)用程序的基石。它確保業(yè)務(wù)規(guī)則和領(lǐng)域不變條件(invariants)得到一致地強制執(zhí)行,同時保持清晰的關(guān)注點分離(separation of concerns),并防止無效狀態(tài)破壞您的領(lǐng)域模型。

理解領(lǐng)域驗證基礎(chǔ)

領(lǐng)域驗證與輸入驗證(input validation)有著根本性的不同。輸入驗證確保數(shù)據(jù)在應(yīng)用程序邊界處滿足基本格式要求,而領(lǐng)域驗證則強制執(zhí)行定義領(lǐng)域?qū)ο笥行缘臉I(yè)務(wù)規(guī)則和不變條件。在 DDD 中,領(lǐng)域?qū)嶓w(domain entities)應(yīng)該始終是有效的實體——絕不應(yīng)存在實體可以處于無效狀態(tài)的情況。

“始終有效的領(lǐng)域模型”(Always-Valid Domain Model)原則指出,領(lǐng)域?qū)ο髴?yīng)該保護自己,避免變成無效狀態(tài)。這種方法提供了幾個關(guān)鍵優(yōu)勢:

消除防御性編程(Defensive Programming):一旦創(chuàng)建,您可以信任領(lǐng)域?qū)ο筇幱谟行顟B(tài),無需進行持續(xù)的驗證檢查

集中化業(yè)務(wù)邏輯:所有驗證規(guī)則都存在于領(lǐng)域?qū)ο蟊旧?/span>

降低維護負(fù)擔(dān):消除了代碼庫中分散的驗證檢查

兩種主要的驗證方法

1. 基于異常的驗證(Exception-Based Validation)

傳統(tǒng)方法使用異常來指示驗證失敗:

public sealedclassEmail : ValueObject
{
    privatestaticreadonly Regex EmailRegex = new(
        @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
        RegexOptions.Compiled | RegexOptions.IgnoreCase);

    publicstring Value { get; }

    private Email(string value)
    {
        Value = value;
    }

    public static Email Create(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            thrownew DomainException("Email cannot be empty");

        if (value.Length > 255)
            thrownew DomainException("Email cannot exceed 255 characters");

        if (!EmailRegex.IsMatch(value))
            thrownew DomainException("Invalid email format");

        returnnew Email(value.ToLowerInvariant());
    }
}

優(yōu)勢:

? 通過立即終止操作清晰指示失敗

? 對大多數(shù)開發(fā)者來說很熟悉

? 堆棧跟蹤有助于調(diào)試

劣勢:

? 異常創(chuàng)建帶來的性能開銷

? 難以收集多個驗證錯誤

? 異常處理的復(fù)雜性

2. 結(jié)果模式驗證(Result Pattern Validation)

結(jié)果模式(Result pattern)提供了一種函數(shù)式的錯誤處理方法:

public sealedclassResult<T>
{
    privatereadonly T? _value;
    privatereadonly Error? _error;

    private Result(T value)
    {
        _value = value;
        _error = null;
        IsSuccess = true;
    }

    private Result(Error error)
    {
        _value = default;
        _error = error;
        IsSuccess = false;
    }

    publicbool IsSuccess { get; }
    publicbool IsFailure => !IsSuccess;

    public T Value => IsSuccess
        ? _value!
        : thrownew InvalidOperationException("Cannot access value of failed result");

    public Error Error => IsFailure
        ? _error!
        : thrownew InvalidOperationException("Cannot access error of successful result");

    public static Result<T> Success(T value) => new(value);
    public static Result<T> Failure(Error error) => new(error);
}

優(yōu)勢:

顯式錯誤處理:調(diào)用者必須顯式處理成功/失敗情況

提高性能:避免異常開銷

更易測試:比測試拋出異常的代碼更容易

收集多個錯誤:可以聚合驗證錯誤

劣勢:

冗長:相比異常需要編寫更多代碼

堆棧跟蹤傳播:必須標(biāo)記調(diào)用鏈中的所有方法以返回 Result 對象

用于保護不變條件的守衛(wèi)子句(Guard Clauses)

守衛(wèi)子句提供了一種優(yōu)雅的方式來強制執(zhí)行驗證規(guī)則,同時保持代碼的整潔和可讀性:

public staticclassGuard
{
    public static void NotNull<T>(T value,
        [CallerArgumentExpression(nameof(value))] string? paramName = null)
    {
        if (valueisnull)
            thrownew ArgumentNullException(paramName);
    }

    public static void NotEmpty(string value,
        [CallerArgumentExpression(nameof(value))] string? paramName = null)
    {
        if (string.IsNullOrWhiteSpace(value))
            thrownew DomainException($"{paramName} cannot be empty");
    }

    public static void GreaterThan<T>(T value, T minimum,
        [CallerArgumentExpression(nameof(value))] string? paramName = null)
        where T : IComparable<T>
    {
        if (value.CompareTo(minimum) <= 0)
            thrownew DomainException($"{paramName} must be greater than {minimum}");
    }
}

在領(lǐng)域?qū)嶓w中的用法:

public sealedclassProduct : Entity<ProductId>
{
    publicstring Name { get; privateset; }
    public Money Price { get; privateset; }
    publicint StockQuantity { get; privateset; }

    public Product(string name, Money price, int stockQuantity)
        : base(new ProductId(Guid.NewGuid()))
    {
        Guard.NotEmpty(name, nameof(name));
        Guard.NotNull(price, nameof(price));
        Guard.GreaterThan(stockQuantity, -1, nameof(stockQuantity));

        Name = name;
        Price = price;
        StockQuantity = stockQuantity;
    }
}

領(lǐng)域錯誤目錄(Domain Error Catalogs)

創(chuàng)建集中化的錯誤目錄以提高可維護性:

public staticclassCustomerErrors
{
    publicstaticreadonly Error NameRequired = new("Customer.NameRequired", "Customer name is required");
    publicstaticreadonly Error NameTooLong = new("Customer.NameTooLong", "Customer name cannot exceed 100 characters");
    publicstaticreadonly Error EmailRequired = new("Customer.EmailRequired", "Customer email is required");
    publicstaticreadonly Error EmailInvalid = new("Customer.EmailInvalid", "Customer email format is invalid");
    publicstaticreadonly Error NotFound = new("Customer.NotFound", "Customer not found");
}

public sealed record Error(string Code, string Message); // 錯誤記錄類型

聚合驗證與不變條件(Aggregate Validation and Invariants)

聚合(Aggregates)充當(dāng)一致性邊界(consistency boundaries),必須強制執(zhí)行其內(nèi)部實體之間的不變條件:

public sealedclassOrder : AggregateRoot<OrderId>
{
    privatereadonly List<OrderItem> _items = new();

    public CustomerId CustomerId { get; privateset; }
    public Money TotalAmount { get; privateset; }
    public OrderStatus Status { get; privateset; }

    public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();

    public static Result<Order> Create(CustomerId customerId, List<OrderItem> items)
    {
        // 業(yè)務(wù)規(guī)則:訂單必須至少包含一個項目
        if (!items.Any())
            return Result<Order>.Failure(OrderErrors.EmptyOrder);

        // 業(yè)務(wù)規(guī)則:訂單金額不能超過最大值
        var totalAmount = items.Sum(item => item.Price.Amount * item.Quantity);
        if (totalAmount > 10000)
            return Result<Order>.Failure(OrderErrors.ExceedsMaximumValue);

        var order = new Order(customerId, new Money(totalAmount, "USD"));
        foreach (var item in items)
        {
            order._items.Add(item);
        }

        return Result<Order>.Success(order);
    }
}

與 .NET 10 中 FluentValidation 的集成

雖然領(lǐng)域驗證應(yīng)位于領(lǐng)域?qū)樱╠omain layer),但 FluentValidation 在應(yīng)用層(application layer)對其進行了補充:

public sealedclassCreateCustomerCommandValidator : AbstractValidator<CreateCustomerCommand>
{
    public CreateCustomerCommandValidator()
    {
        RuleFor(x => x.Name)
            .NotEmpty()
            .WithMessage("Customer name is required")
            .MaximumLength(100)
            .WithMessage("Customer name cannot exceed 100 characters");

        RuleFor(x => x.Email)
            .NotEmpty()
            .WithMessage("Customer email is required")
            .EmailAddress()
            .WithMessage("Customer email format is invalid");
    }
}

結(jié)合兩種方法的應(yīng)用層處理程序:

public sealedclassCreateCustomerCommandHandler : IRequestHandler<CreateCustomerCommand, Result<CustomerId>>
{
    privatereadonly ICustomerRepository _customerRepository;
    privatereadonly IUnitOfWork _unitOfWork;

    publicasync Task<Result<CustomerId>> Handle(CreateCustomerCommand request, CancellationToken cancellationToken)
    {
        // 通過工廠方法進行領(lǐng)域驗證
        var customerResult = Customer.Create(request.Name, request.Email);

        if (customerResult.IsFailure)
            return Result<CustomerId>.Failure(customerResult.Error);

        _customerRepository.Add(customerResult.Value);
        await _unitOfWork.SaveChangesAsync(cancellationToken);

        return Result<CustomerId>.Success(customerResult.Value.Id);
    }
}

領(lǐng)域驗證的最佳實踐

選擇正確的驗證策略

在以下情況下使用異常:

? 驗證失敗代表編程錯誤

? 需要立即終止無效操作

? 預(yù)期發(fā)生單一驗證失敗

在以下情況下使用結(jié)果模式:

? 需要收集多個驗證錯誤

? 希望進行顯式錯誤處理

? 性能至關(guān)重要

正確分層驗證

輸入驗證(Input Validation)(應(yīng)用層)

    格式驗證

    必填字段檢查

     基本數(shù)據(jù)類型驗證

業(yè)務(wù)驗證(Business Validation)(領(lǐng)域?qū)?

     業(yè)務(wù)規(guī)則強制執(zhí)行

     不變條件保護

     跨實體驗證

使驗證顯式化

使用業(yè)務(wù)利益相關(guān)者可以理解的清晰、描述性的錯誤消息和代碼。避免層之間的驗證重復(fù)——依靠領(lǐng)域?qū)ο髞砭S護其自身的有效性。

.NET 10 的特定增強功能

.NET 10 帶來了幾項與領(lǐng)域驗證相關(guān)的改進:

增強的性能:運行時優(yōu)化有利于驗證密集的場景

改進的 LINQ:新的 CountBy 和 AggregateBy 方法簡化了驗證聚合

更好的錯誤處理:增強的異常處理和結(jié)果處理

安全性改進:強化的驗證框架和輸入處理

在 .NET 10 中,結(jié)合整潔架構(gòu)和 DDD 的領(lǐng)域驗證為構(gòu)建可維護、業(yè)務(wù)導(dǎo)向的應(yīng)用程序提供了堅實的基礎(chǔ)。通過在領(lǐng)域?qū)邮褂檬匦l(wèi)子句和結(jié)果模式等適當(dāng)模式實施驗證,同時保持清晰的關(guān)注點分離,您可以創(chuàng)建既技術(shù)上合理又與業(yè)務(wù)需求保持一致的系統(tǒng)。關(guān)鍵是為您的特定用例選擇正確的驗證策略,并確保業(yè)務(wù)規(guī)則在您的領(lǐng)域模型中得到一致的強制執(zhí)行。

責(zé)任編輯:武曉燕 來源: 架構(gòu)師老盧
相關(guān)推薦

2010-02-01 09:54:43

2024-07-26 10:01:16

2009-07-06 21:11:04

2017-11-17 05:39:27

DDD建模模型

2024-10-09 12:03:06

2025-05-12 08:06:45

2012-12-12 13:15:43

安全監(jiān)控監(jiān)控

2023-02-15 13:50:58

DDD戰(zhàn)略設(shè)計

2023-02-20 14:44:22

DDD領(lǐng)域模型

2021-09-08 09:22:23

領(lǐng)域驅(qū)動設(shè)計

2009-01-18 09:17:00

2022-04-19 08:15:53

DDD領(lǐng)域建模實戰(zhàn)

2023-02-19 12:44:07

領(lǐng)域事件DDD

2010-09-29 09:33:29

2010-09-02 16:31:54

2023-02-26 10:59:51

2017-07-14 10:55:05

2024-06-18 08:21:31

2023-05-29 08:00:00

ChatGPT人工智能機器學(xué)習(xí)
點贊
收藏

51CTO技術(shù)棧公眾號