一、什麼是洋蔥架構
洋蔥架構(Onion Architecture)是由Jeffrey Palermo提出的一種軟體架構模式,用於實現可擴展、可維護和可測的應用程序。
它的基本思想是將應用程序分為多個層,每個層都依賴於下一層,並通過依賴注入實現。
這種層次結構就像一個洋蔥,每一層都像是裹在洋蔥外層的一層,通過不斷向內擴展,就能構建出一個穩定、可擴展的應用程序架構。
二、洋蔥架構的結構
洋蔥架構可以分為四個主要的層:
1. UI層
UI層是應用程序的用戶介面部分,可以是Web應用、桌面應用或移動設備應用。
UI層負責與用戶交互,接收用戶輸入,向外部系統顯示信息、狀態等。但它並不負責任何業務邏輯,它只是將請求轉發給下一層。
2. 應用程序層
應用程序層包含應用程序的業務邏輯和應用程序流程。它接收由UI層傳遞過來的請求,將數據處理後傳遞到下一層。
應用程序層中的方法需要具備可復用性,它們應該是獨立的,這樣可以在其它應用程序中重複使用。
3. 領域層
領域層定義了業務邏輯和實體。它是業務處理的核心,包含了業務邏輯的實現代碼。
領域層的主要作用是封裝所有與業務相關的代碼,並對外表現出一套乾淨、簡單的介面。因此它需要與具體的技術實現解耦,以便於將來的維護和替換。
4. 基礎設施層
基礎設施層提供了應用程序所需的所有支持,例如資料庫、文件系統、網路連接和郵件等。
基礎設施層負責將領域層和外部系統連接起來,它是業務邏輯和外部系統之間的橋樑,為領域層提供必要的支持。
三、洋蔥架構的優點
洋蔥架構的優點主要有以下幾點:
1. 可擴展性
由於每個層都是獨立的,它們之間的耦合很鬆散,容易擴展。可以在每個層中添加更多的組件或邏輯,而不影響其它層的功能。
2. 可測試性
洋蔥架構可以很容易地進行單元測試、集成測試和功能測試,因為每個層都是可測試的。
3. 可維護性
由於業務邏輯封裝在領域層中,所以更容易進行維護、修復和升級。
4. 可重用性
由於每個層都是獨立的,因此它們可以在多個項目中重複使用。
四、示例代碼
1. 用戶服務介面
public interface IUserService { bool ValidateUserCredentials(string username, string password); User GetUserById(int id); IEnumerable GetAllUsers(); void CreateUser(User user); }
2. 用戶服務實現
public class UserService : IUserService { private readonly IUserRepository userRepository; public UserService(IUserRepository userRepository) { this.userRepository = userRepository; } public bool ValidateUserCredentials(string username, string password) { return userRepository .GetUserByUsername(username)? .Password .Equals(password) ?? false; } public User GetUserById(int id) { return userRepository.GetUserById(id); } public IEnumerable GetAllUsers() { return userRepository.GetAllUsers(); } public void CreateUser(User user) { userRepository.CreateUser(user); } }
3. 用戶倉儲介面
public interface IUserRepository { User GetUserById(int id); IEnumerable GetAllUsers(); void CreateUser(User user); User GetUserByUsername(string username); }
4. 用戶倉儲實現
public class UserRepository : IUserRepository { private readonly ApplicationDbContext context; public UserRepository(ApplicationDbContext context) { this.context = context ?? throw new ArgumentNullException(nameof(context)); } public User GetUserById(int id) { return context.Users.FirstOrDefault(u => u.Id == id); } public IEnumerable GetAllUsers() { return context.Users.ToList(); } public void CreateUser(User user) { context.Users.Add(user); context.SaveChanges(); } public User GetUserByUsername(string username) { return context.Users.FirstOrDefault(u => u.Username.Equals(username, StringComparison.OrdinalIgnoreCase)); } }
5. 控制器
[ApiController] public class UserController : ControllerBase { private readonly IUserService userService; public UserController(IUserService userService) { this.userService = userService; } [HttpPost] [Route("api/users")] public IActionResult CreateUser([FromBody] CreateUserRequest request) { var user = new User { Username = request.Username, Password = request.Password }; userService.CreateUser(user); return Ok(); } [HttpGet] [Route("api/users")] public IActionResult GetAllUsers() { var users = userService.GetAllUsers(); var userDtos = users.Select(u => new UserDto { Id = u.Id, Username = u.Username }); return Ok(userDtos); } [HttpGet] [Route("api/users/{id}")] public IActionResult GetUserById(int id) { var user = userService.GetUserById(id); var userDto = new UserDto { Id = user.Id, Username = user.Username }; return Ok(userDto); } [HttpPost] [Route("oauth/token")] public IActionResult GetToken([FromBody] GetTokenRequest request) { if (userService.ValidateUserCredentials(request.Username, request.Password)) { return Ok(new { AccessToken = "dummyAccessToken" }); } else { return Unauthorized(); } } }
原創文章,作者:CQCRV,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/334551.html