VieTopikKhoá học
  • Games
  • Cá nhân
Tải app
© 2026 VieTopikChính sách bảo mậtĐiều khoản sử dụngCài appEnglish
  • Trang chủ
  • Học
  • Luyện thi
  • Cẩm nang
  • Games
  • Cá nhân
Kiến trúc và chất lượng codeKiến trúc ứng dụng
Bài 16/17
6 phút

Clean Architecture

Bình luận
Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Chia tầng xong vẫn còn một câu hỏi: tầng nghiệp vụ gọi xuống tầng dữ liệu, vậy nó có phụ thuộc vào Oracle không? Nếu có, đổi database là phải sửa cả quy tắc nghiệp vụ. Clean Architecture đảo chiều phụ thuộc để phần lõi không biết gì về database hay giao diện.

Khái niệm

🧅 Clean Architecture: cách tổ chức ứng dụng đặt nghiệp vụ ở lõi, database và giao diện ở vòng ngoài, mọi phụ thuộc chỉ hướng từ ngoài vào lõi.

Vòng Chứa gì Được phép biết
Core (lõi) Product, IProductStore, OrderService không biết vòng nào khác
Infrastructure ShopDbContext, DbProductStore, EF Core Core
Giao diện API ShopApi, app ShopDesk Core và Infrastructure

Điểm mấu chốt: IProductStore nằm trong Core (không còn ở tầng dữ liệu như bài trước), còn class implement nó nằm ở Infrastructure. Đây là DIP của khoá OOP, áp dụng cho cả ứng dụng.

ShopApi, ShopDesk Infrastructure: DbProductStore Core: OrderService, IProductStore
Phụ thuộc hướng vào lõi

Ví dụ

Đặt hàng xong cần gửi email. Core cần "gửi email" nhưng không được biết máy chủ email cụ thể, nên Core khai báo interface:

// Core
public interface IEmailSender
{
    void Send(string to, string message);
}

public class CheckoutService
{
    private readonly IEmailSender _email;

    public CheckoutService(IEmailSender email)
    {
        _email = email;
    }

    public void Complete(string orderCode, string email)
    {
        _email.Send(email, "Đã nhận đơn " + orderCode);
    }
}

Infrastructure implement interface đó bằng công nghệ cụ thể:

// Infrastructure
public class ConsoleEmailSender : IEmailSender
{
    public void Send(string to, string message)
    {
        Console.WriteLine($"Gửi {to}: {message}");
    }
}
  • CheckoutService chỉ biết IEmailSender. Nó không biết email gửi bằng gì.
  • Đổi sang dịch vụ email khác chỉ cần viết một class mới ở Infrastructure.
  • Hai phần được ghép ở composition root như bài Tách giao diện và dữ liệu: Program.cs của API hay Main của WinForms.

Thử ngay

Tạo một project console bằng dotnet new console, dán ba class trên vào Program.cs, thêm ba dòng này ở đầu file rồi chạy. Program.cs đóng vai composition root:

// Program.cs của project console
IEmailSender sender = new ConsoleEmailSender();
var checkout = new CheckoutService(sender);
checkout.Complete("DH1", "an@shop.vn");

Đoán trước khi chạy: dòng in ra là gì, và class nào in nó?

Xem kết quả
Gửi an@shop.vn: Đã nhận đơn DH1

CheckoutService của Core gọi Send qua interface, còn ConsoleEmailSender của Infrastructure mới là class in ra.

Lỗi hay gặp

Đặt interface ở Infrastructure. Core phải dùng tới Infrastructure để lấy interface, tức lõi lại phụ thuộc vòng ngoài và kéo theo EF Core, Oracle.

# SAI — lõi phụ thuộc vòng ngoài
Core chứa: OrderService
Infrastructure chứa: IProductStore, DbProductStore
Core tham chiếu Infrastructure
# ĐÚNG — interface ở lõi, vòng ngoài implement
Core chứa: IProductStore, OrderService
Infrastructure chứa: DbProductStore
Infrastructure tham chiếu Core

Tóm tắt

  • Core chứa entity, interface và quy tắc nghiệp vụ, không biết database hay giao diện.
  • Infrastructure implement các interface của Core bằng công nghệ cụ thể.
  • Phụ thuộc chỉ hướng từ ngoài vào lõi.
  • Interface nằm ở Core, class implement nằm ở vòng ngoài.
Chia tầngTách solution nhiều project

Bình luận

Đang tải bình luận…

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt