Clean Architecture
1. Layers
Phần tiêu đề “1. Layers”┌─────────────────────────────────────┐│ Presentation │ Views, ViewModels├─────────────────────────────────────┤│ Domain │ Use Cases, Entities├─────────────────────────────────────┤│ Data │ Repositories, API└─────────────────────────────────────┘2. Domain Layer
Phần tiêu đề “2. Domain Layer”// Entitystruct User: Identifiable { let id: Int let name: String let email: String}
// Repository Protocolprotocol UserRepository { func getUsers() async throws -> [User] func getUser(id: Int) async throws -> User}
// Use Caseclass GetUsersUseCase { private let repository: UserRepository
init(repository: UserRepository) { self.repository = repository }
func execute() async throws -> [User] { try await repository.getUsers() }}3. Data Layer
Phần tiêu đề “3. Data Layer”class UserRepositoryImpl: UserRepository { private let apiClient: APIClient
func getUsers() async throws -> [User] { let response: [UserDTO] = try await apiClient.get("/users") return response.map { $0.toDomain() } }}
struct UserDTO: Codable { let id: Int let name: String let email: String
func toDomain() -> User { User(id: id, name: name, email: email) }}4. Presentation Layer
Phần tiêu đề “4. Presentation Layer”@MainActorclass UserListViewModel: ObservableObject { private let getUsersUseCase: GetUsersUseCase
@Published var users: [User] = []
init(getUsersUseCase: GetUsersUseCase) { self.getUsersUseCase = getUsersUseCase }
func loadUsers() async { users = try await getUsersUseCase.execute() }}📝 Benefits
Phần tiêu đề “📝 Benefits”- Clear boundaries between layers
- Easy to test each layer
- Scalable for large apps
- Independent of frameworks