Middle+
Czy znasz architekturę z cyklem VIP?
sobes.tech AI
Odpowiedź od AI
VIP (Widok, Interaktor, Prezenter) to wzorzec architektoniczny, który stanowi wariant Czystej Architektury, stosowany w rozwoju iOS do rozdzielenia odpowiedzialności i poprawy testowalności kodu. Podstawą jest jednokierunkowy przepływ danych między komponentami.
Komponenty VIP:
- Widok: Wyświetla dane i wysyła akcje użytkownika (akcje użytkownika) do Interaktora. Widok (UIView, UIViewController lub po prostu protokół) nie zawiera logiki biznesowej.
- Interaktor: Zawiera logikę biznesową. Odbiera akcje od Widoku, wykonuje niezbędne operacje (np. dostęp do danych, obliczenia) i wysyła wynik do Prezenter.
- Prezenter: Odbiera dane od Interaktora, formatuje je do wyświetlenia i wysyła do Widoku. Nie zawiera logiki biznesowej, odpowiada tylko za prezentację danych.
Cykl interakcji:
- Użytkownik wykonuje akcję w Widoku.
- Widok wysyła "żądanie" (request - struct/enum) do Interaktora.
- Interaktor przetwarza żądanie, wykonuje logikę biznesową i wysyła "odpowiedź" (response - struct/enum) do Prezenter.
- Prezenter otrzymuje odpowiedź, formatuje dane w "ViewModel" (struct/enum) i wysyła do Widoku.
- Widok otrzymuje ViewModel i aktualizuje UI.
Dodatkowe komponenty (opcjonalnie):
- Router: Zarządza nawigacją między modułami VIP (scenami). Zazwyczaj wywoływany przez Interaktora lub Prezenter.
- Worker: Komponent Interaktora odpowiedzialny za wykonywanie konkretnych zadań (np. zapytania sieciowe, praca z Core Data).
Główne zalety VIP:
- Rozdzielenie odpowiedzialności: Jasne rozdzielenie między UI, logiką biznesową i logiką prezentacji.
- Testowalność: Łatwo testować każdy komponent osobno, mockując zależności.
- Łatwość utrzymania: Zmiany w jednym komponencie mają mniejszy wpływ na inne.
Przykład struktury folderów dla modułu VIP (UserScene):
UserScene/
├── UserViewController.swift
├── UserInteractor.swift
├── UserPresenter.swift
├── UserRouter.swift
├── UserModels.swift // Struktury dla Request, Response, ViewModel
├── UserProtocols.swift // Protokoły do komunikacji między komponentami
Przykład interakcji (ładowanie danych użytkownika):
// W UserViewController
func viewDidLoad() {
super.viewDidLoad()
interactor?.fetchUserData(request: UserModels.FetchUser.Request())
}
// W UserInteractor
func fetchUserData(request: UserModels.FetchUser.Request) {
// ... logika biznesowa ładowania danych ...
let response = UserModels.FetchUser.Response(userData: fetchedData)
presenter?.presentUserData(response: response)
}
// W UserPresenter
func presentUserData(response: UserModels.FetchUser.Response) {
let viewModel = UserModels.FetchUser.ViewModel(
displayName: response.userData.name,
displayEmail: response.userData.email
)
viewController?.displayUserData(viewModel: viewModel)
}
// W UserViewController (implementacja protokołu UserDisplayLogic)
func displayUserData(viewModel: UserModels.FetchUser.ViewModel) {
nameLabel.text = viewModel.displayName
emailLabel.text = viewModel.displayEmail
}