在我繼續我的後端開發之旅時,一個問題一直困擾著我:為什麼我們不能把所有的邏輯都寫在控制器裡?感覺很簡單,抓取資料、應用一些規則、更新資料庫,所有這些都在一個地方完成。哦,我的確這麼做了,但我知道這對大公司來說效率不高,而且你不可能用這樣的程式碼打入大公司的市場,但我從未真正理解它,也不知道為什麼。

但現實是:雖然這對小型業餘專案來說可能沒問題,但在大型應用程式(例如金融系統)中,它很快就會變得混亂。這就是為什麼大公司堅持使用分層架構的原因。將職責劃分為控制器、業務邏輯(服務)和儲存庫

很長一段時間裡,我無法完全理解這種分離的重要性。我研究、實驗,也曾苦苦掙扎,直到有一天我終於明白了。一旦我理解了,它就徹底改變了我對軟體架構的思考方式。我知道很多人也走著同樣的路,所以我想用簡單易懂的語言來分享這些知識,讓大家最終理解。

讓我們透過簡單的類比、清晰的圖表和實用的程式碼來深入研究它。


將您的應用程式視為一家公司

| 層 | 它是誰 | 它做什麼 |

| ---------------- | ------------------- | -------------------------------------------------------------- |

|控制員| 前台接待員 | 接收請求並傳遞 |

|服務| 銀行經理 | 應用規則、做決策、執行政策 |

|儲存庫| 記錄員 | 取得並更新系統中的記錄 |

| ILogger | 安全攝影機 | 保存發生的事情的歷史記錄(稽核/日誌)|

| Serilog/NLog | 儲藏室 | 決定日誌的儲存位置|


流程(圖)


[ User Request ]

      ↓

[ Controller ] → Receives request and passes it along to the Services

      ↓

[ Service ] → Applies business rules and logic

      ↓

[ Repository ] → Talks to the database (fetching and updating details only)

控制者:前台

控制器是入口點。它不做決策,也不與資料庫互動;它只是接收請求並轉發。


[ApiController]

[Route("api/transfer")]

public class TransferController : ControllerBase

{

   private readonly ITransferService \\\_service;

   public TransferController(ITransferService service)

   {

       _service = service;

   }

   [HttpPost]

   public IActionResult TransferMoney([FromBody] TransferRequest request)

   {

       _service.Transfer(request.FromAccount, request.ToAccount, request.Amount);

       return Ok("Transfer completed");

   }

}

服務:銀行經理

服務(業務邏輯層)應用規則。例如,“發送者是否有足夠的錢進行轉帳?”


public class TransferService : ITransferService

{

\    private readonly IAccountRepository \\\_repository;

\&nbsp;   private readonly ILogger<TransferService> \\\_logger;

\&nbsp;   public TransferService(IAccountRepository repository, ILogger<TransferService> logger)

\&nbsp;   {

\&nbsp;       \\\_repository = repository;

\&nbsp;       \\\_logger = logger;

\&nbsp;   }

\&nbsp;   public void Transfer(string fromAcc, string toAcc, decimal amount)

\&nbsp;   {

\&nbsp;       var from = \\\_repository.GetAccount(fromAcc);

\&nbsp;       var to = \\\_repository.GetAccount(toAcc);

\&nbsp;       if (from.Balance < amount)

\&nbsp;       {

\&nbsp;           \\\_logger.LogWarning("Insufficient funds for account {Account}", fromAcc);

\&nbsp;           throw new Exception("Insufficient funds");

\&nbsp;       }

\&nbsp;       from.Balance -= amount;

\&nbsp;       to.Balance += amount;

\&nbsp;       \\\_repository.UpdateAccount(from);

\&nbsp;       \\\_repository.UpdateAccount(to);

\&nbsp;       \\\_logger.LogInformation("Transferred {Amount} from {From} to {To}", amount, fromAcc, toAcc);

\&nbsp;   }

}

儲存庫:記錄員

儲存庫是資料存取發生的地方。沒有規則,沒有決策——只是讀取和寫入資料。


public class AccountRepository : IAccountRepository

{

\&nbsp;   private readonly BankingDbContext \\\_context;

\&nbsp;   private readonly ILogger<AccountRepository> \\\_logger;

\&nbsp;   public AccountRepository(BankingDbContext context, ILogger<AccountRepository> logger)

\&nbsp;   {

\&nbsp;       \\\_context = context;

\&nbsp;       \\\_logger = logger;

\&nbsp;   }

\&nbsp;   public Account GetAccount(string accountId)

\&nbsp;   {

\&nbsp;       \\\_logger.LogInformation("Fetching account {AccountId}", accountId);

\&nbsp;       return \\\_context.Accounts.FirstOrDefault(a => a.Id == accountId);

\&nbsp;   }

\&nbsp;   public void UpdateAccount(Account account)

\&nbsp;   {

\&nbsp;       \\\_context.Accounts.Update(account);

\&nbsp;       \\\_context.SaveChanges();

\&nbsp;       \\\_logger.LogInformation("Updated account {AccountId}", account.Id);

\&nbsp;   }

}

記錄:安全攝影機

在金融領域,日誌記錄至關重要。每筆交易、每條成功或每條錯誤都必須追蹤。這正是ILogger 的用武之地。


\\\_logger.LogInformation("Transaction {TransactionId} completed at {Time}", transaction.Id, DateTime.UtcNow);

\\\_logger.LogError("Failed to process transaction {TransactionId}", transaction.Id);

但是 ILogger 只是一個介面。你仍然需要像SerilogNLog這樣的日誌提供者來決定將這些日誌儲存在何處(檔案、雲端、資料庫等)。


// Program.cs setup example with Serilog

Log.Logger = new LoggerConfiguration()

\&nbsp;   .WriteTo.File("logs/transactions.txt")

\&nbsp;   .CreateLogger();

builder.Host.UseSerilog();

摘要:誰做什麼

| 層 | 職責 | 類比 |

| ------------ | -------------------------------------- | ---------------- |

| 控制器 | 接受請求並回傳回應 | 前台接待員 |

| 服務 | 應用業務規則 | 銀行經理 |

| 儲存庫 | 處理資料存取 | 記錄員 |

| ILogger | 記錄操作、錯誤與審核 | 安全攝影機 |

| Serilog/NLog | 儲存日誌(檔案、資料庫、雲端等)| 儲藏室 |


大公司與小專案

  • 小型專案:你可以把控制器裡的所有東西混合起來。這樣可以工作一段時間。

  • 大公司:這種架構是強制性的。它開發的應用程式:

  • 更容易測試

  • 更容易擴展

  • 更易於維護

  • 更安全(特別是與金錢相關的系統)

請這樣查看:

  • 如果是關於處理 API 請求 →控制器

  • 如果是關於規則、邏輯或決策 →服務

  • 如果是關於取得或儲存資料 →儲存庫

  • 如果是關於追蹤活動→ ILogger (使用 Serilog/NLog 來儲存它)


最後的想法

如果你正在開發一個業餘專案,你可以偷工減料。但如果你的目標是在大公司工作,或是開發能夠持續發展和發展的軟體,那麼這種分層架構就是你必須遵循的基礎。

時時思考:前台職員、銀行經理、記錄員和保全攝像頭,每個人都有各自的職責。這有助於您記住並了解程式碼應該屬於哪個分類/部分。將它們分開管理,可以讓您的系統保持整潔、可擴展且專業。

圖形來源:Ramesh Fadatare

LinkedIn: LinkedIn

推特: Twitter

Instagram: Instagram


原文出處:https://dev.to/omotola_odumosu_/coding-architecture-layers-why-big-companies-use-it-in-c-and-why-you-should-too-1lgo


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝10   💬6   ❤️11
448
🥈
我愛JS
📝1   💬6   ❤️4
93
🥉
AppleLily
📝1   💬4   ❤️1
46
#4
💬2  
6
#5
💬1  
5
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次