25. 架构实战
架构的目标是“可维护、可扩展、可测试”。核心做法:拆分职责,业务与 UI 解耦,依赖可替换。
一、MVC 的问题点
- Controller 过胖
- 网络、业务、UI 混在一起
- 单元测试难做
二、MVVM 最小实现
1. Model
struct User: Decodable {
let id: Int
let name: String
}
2. ViewModel
final class UserViewModel {
private let service: UserService
init(service: UserService) {
self.service = service
}
var onUpdate: ((User) -> Void)?
var onError: ((Error) -> Void)?
func loadUser() {
service.fetch { [weak self] result in
switch result {
case .success(let user): self?.onUpdate?(user)
case .failure(let error): self?.onError?(error)
}
}
}
}
3. ViewController
final class UserVC: UIViewController {
private let nameLabel = UILabel()
private let viewModel: UserViewModel
init(viewModel: UserViewModel) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func viewDidLoad() {
super.viewDidLoad()
viewModel.onUpdate = { [weak self] user in
DispatchQueue.main.async { self?.nameLabel.text = user.name }
}
viewModel.onError = { error in
print(error)
}
viewModel.loadUser()
}
}
三、服务层与协议解耦
protocol UserService {
func fetch(completion: @escaping (Result<User, Error>) -> Void)
}
final class RemoteUserService: UserService {
func fetch(completion: @escaping (Result<User, Error>) -> Void) {
// 网络请求
}
}
通过协议,后续可以替换成 MockService 进行测试。
四、Repository 分层
protocol UserRepository {
func fetch(completion: @escaping (Result<User, Error>) -> Void)
}
final class UserRepositoryImpl: UserRepository {
private let remote: UserService
private let cache: UserCache
init(remote: UserService, cache: UserCache) {
self.remote = remote
self.cache = cache
}
func fetch(completion: @escaping (Result<User, Error>) -> Void) {
if let cached = cache.load() {
completion(.success(cached))
return
}
remote.fetch { result in
if case .success(let user) = result { self.cache.save(user) }
completion(result)
}
}
}
五、模块化边界
Feature:具体业务模块Core:网络、存储、工具UI:通用组件
结构示例:
App
├─ Core
├─ Network
├─ Storage
├─ Features
│ ├─ Home
│ ├─ Profile
└─ UIComponents
六、依赖注入
final class AppContainer {
let userService: UserService
let userRepository: UserRepository
init() {
userService = RemoteUserService()
userRepository = UserRepositoryImpl(remote: userService, cache: MemoryUserCache())
}
func makeUserVC() -> UIViewController {
let vm = UserViewModel(service: userService)
return UserVC(viewModel: vm)
}
}
架构不是越复杂越好,目标是让代码在长期迭代中保持可读与可控。