MVP (Model-View-Presenter) — Presenter ViewContract interfeysi orqali Model va View o'rtasida vositachi bo'lib xizmat qiladigan arxitektura namunasi. MVC dan farqli o'laroq, bunda Controller to'g'ridan-to'g'ri UIKit orqali View ni boshqaradi, Presenter freymvorkka bog'liq emas — abstraksiya orqali ishlaydi, bu uni Android SDK yoki UIKit siz test qilinadigan qiladi. MVP Android ishlanmasida Jetpack paydo bo'lishidan oldin keng qo'llanilgan va legacy loyihalar uchun dolzarb bo'lib qolmoqda. Batafsil Martin Faulerning maqolasida.
Asosiy
MVP (Model-View-Presenter) — 2000-yillarning boshida Martin Fauler tomonidan foydalanuvchi interfeysining test qilinishini yaxshilash uchun MVC ning evolyutsiyasi sifatida taklif qilingan arxitektura namunasi. Model ma'lumotlar va biznes mantiqni boshqaradi, View ko'rsatish va foydalanuvchi kiritishini qayta ishlash uchun javobgar, Presenter — View dan hodisalarni oladigan, Model dan ma'lumotlarni chiqaradigan va ko'rsatish uchun holatni shakllantiradigan markaziy komponent.
MVP ni MVC dan asosiy farqi — Presenter View ga to'g'ridan-to'g'ri havolaga ega emas. Buning o'rniga Presenter ViewContract interfeysi orqali View bilan o'zaro aloqa qiladi. View bu interfeysni amalga oshiradi va o'zini Presenter ga uzatadi. Bu UIKit (iOS) yoki Android Framework ga bog'liqlikni uzadi — Presenter ViewContract ning mock amalga oshirilishi bilan izolyatsiya qilingan holda test qilinadi. MVC da controller UIViewController to'g'ridan-to'g'ri UILabel ni yangilaydi, MVP da Presenter view.showName(name) metodini chaqiradi, View esa qanday ko'rsatishni hal qiladi.
| Komponent | Mas'uliyat | Test qilinish |
|---|---|---|
| Model | Ma'lumotlar, biznes mantiq, tarmoq chaqiruvlari | Unit-testlar (UI ga bog'liq emas) |
| View | UI ni ko'rsatish, hodisalarni Presenter ga uzatish | Interfeys orqali mock amalga oshirish |
| Presenter | Biznes mantiq, holatni boshqarish, navigatsiya | Unit-testlar (ViewContract mock orqali) |
MVP dagi yagona mas'uliyat printsipi MVC dan qattiqroq saqlanadi: View faqat renderlash uchun javobgar, Model — ma'lumotlar uchun, Presenter — mantiq va muvofiqlashtirish uchun. Haqiqiy loyihalarda Presenter ekran kodining 40–60% ini, View — 20–30% ini, Model — 20–30% ini tashkil qiladi. Bunday taqsimot Android emulyatori yoki iOS simulyatorini ishga tushirmasdan asosiy biznes mantiqni test qilish imkonini beradi.
MVP Android-da Activity yoki Fragment ni ViewContract ni amalga oshiradigan View sifatida ishlatadi — ma'lumotlarni ko'rsatish metodlari bilan interfeys. Presenter Activity da yaratiladi, View ni o'ziga bog'laydi va yuklashni boshqaradi. Ekran aylantirilganda Activity qayta yaratiladi — Presenter retain-fragment yoki tashqi saqlash orqali saqlanishi mumkin, bu sof MVC ga xos bo'lgan holat yo'qotish muammosini hal qiladi.
// ViewContract — Presenter ni View bilan bog'lash uchun interfeys
interface UserView {
fun showLoading()
fun hideLoading()
fun showUser(user: User)
fun showError(message: String)
}
// Presenter — test qilinadigan mantiq qatlami
class UserPresenter(
private val repository: UserRepository
) {
private var view: UserView? = null
fun attachView(view: UserView) {
this.view = view
}
fun detachView() {
view = null
}
fun loadUser(userId: Int) {
view?.showLoading()
repository.getUser(userId) { result ->
view?.hideLoading()
result.onSuccess { user ->
view?.showUser(user)
}.onFailure { e ->
view?.showError(e.message ?: "Noma'lum xato")
}
}
}
}
// View (Activity) interfeysni amalga oshiradi
class UserActivity : AppCompatActivity(), UserView {
private val presenter = UserPresenter(UserRepository())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter.attachView(this)
presenter.loadUser(42)
}
override fun onDestroy() {
presenter.detachView()
super.onDestroy()
}
override fun showUser(user: User) { /* UI ni yangilash */ }
override fun showLoading() { /* ProgressBar ko'rsatish */ }
override fun hideLoading() { /* ProgressBar yashirish */ }
override fun showError(message: String) { /* Snackbar ko'rsatish */ }
}
Hayot aylanishini boshqarish — Android da MVP ning asosiy muammosi. Activity ekran aylantirilganda yo'q qilinadi va presenter.attachView() onCreate() da qayta chaqiriladi. Ma'lumot yuklashi asinxron bo'lsa (RxJava, korutinlar), tugallanish vaqtida View ajratilgan bo'lishi mumkin. Yechim — detachView() da obunalarni bekor qilish yoki Support Library dan Loader ishlatish (Jetpack bo'lmagan loyihalar uchun). IT Sectr da yillar davomida tijoriy loyihalarda MVP + RxJava kombinatsiyasini qo'lladik — namuna barqaror, lekin obunalarni boshqarishda intizom talab qiladi.
Retain-fragmentlar — ekran aylantirilganda Presenter ni saqlash mexanizmi. UI siz fragment (setRetainInstance(true)) Activity dan uzoqroq yashaydi va Presenter ga havolani saqlaydi. Activity qayta yaratilganda fragment bir xil Presenter ni yangi Activity ga uzatadi. Retain-fragmentlar AndroidX bilan eskirgan deb topilgan, ammo ularning pre-Jetpack analogi (Fragment.setRetainInstance) hali ham legacy loyihalarda ishlaydi. Zamonaviy ishlanmada Google retain-fragmentlar o'rniga ViewModel ni tavsiya qiladi.
MVP iOS-da View protokoli orqali quriladi. UIViewController protokolni amalga oshiradi, Presenter UIKit ni import qilmaydi va toza test qilinadi. Apple MVC dan farqli o'laroq, bunda UIViewController o'zi mantiq va to'g'ridan-to'g'ri IBOutlet bog'lanishlarini o'z ichiga oladi, Presenter holatni boshqaradi va View ga protokol metodlari orqali buyruq beradi. View qarorlar qabul qilmaydi — Presenter buyruqlarini bajaradi: showUser, showLoading, navigateToProfile.
import Foundation
// View Protocol — Presenter uchun abstraksiya
protocol UserViewProtocol: AnyObject {
func showLoading()
func hideLoading()
func display(user: User)
func displayError(message: String)
}
// Presenter — toza mantiq, UIKit siz
final class UserPresenter {
private weak var view: UserViewProtocol?
private let service: UserServiceProtocol
init(service: UserServiceProtocol) {
self.service = service
}
func attach(view: UserViewProtocol) {
self.view = view
}
func detach() {
view = nil
}
func loadUser(id: Int) {
view?.showLoading()
service.fetchUser(id: id) { [weak self] result in
guard let self else { return }
self.view?.hideLoading()
switch result {
case .success(let user):
self.view?.display(user: user)
case .failure(let error):
self.view?.displayError(message: error.localizedDescription)
}
}
}
}
// View (UIViewController) protokolni amalga oshiradi
final class UserViewController: UIViewController, UserViewProtocol {
private let presenter = UserPresenter(service: UserService())
override func viewDidLoad() {
super.viewDidLoad()
presenter.attach(view: self)
presenter.loadUser(id: 42)
}
func display(user: User) {
nameLabel.text = user.name
}
// ... protokolning qolgan metodlari
}
Weak reference View ga — iOS MVP da majburiy shart. UIViewController yo'q qilinishi mumkin (navigatsiya stekidan pop), uning Presenter dagi closure i retain cycle yaratadi. Zaif havola (weak var) View ekrandan chiqqanda, Presenter da asinxron operatsiyalar mavjudligidan qat'i nazar, bo'shatilishini kafolatlaydi. Android da o'xshash muammo detachView() orqali hal qilinadi — onDestroy() dagi chaqiruv View ga havolani nolga tenglashtiradi.
Passive View vs Supervising Controller — Martin Faulerdan MVP ning ikki varianti. Passive View: View mantiqni o'z ichiga olmaydi, Presenter to'liq holatni boshqaradi. Supervising Controller: View o'zi oddiy ma'lumot bog'lashni amalga oshiradi (masalan, data binding orqali), Presenter faqat murakkab stsenariylarga aralashadi. Mobil ishlanmada Passive View ko'proq qo'llaniladi — maksimal test qilinish va ekran holatining bashorat qilinishini beradi.
MVP va MVC o'rtasidagi asosiy farq — View bilan bog'lanish usuli. MVC da Controller View ga to'g'ridan-to'g'ri havolaga ega (UIViewController.IBOutlets, Activity.findViewById). MVP da Presenter ViewContract interfeysi orqali View bilan o'zaro aloqa qiladi. Bu farq test qilinishni tubdan o'zgartiradi: ViewContract ni amalga oshiradigan Mock ob'ekti Presenter mantiqini ilova, emulyator va UI freymvorkni ishga tushirmasdan tekshirish imkonini beradi.
| Mezon | MVC | MVP |
|---|---|---|
| View bilan bog'lanish | To'g'ridan-to'g'ri (Controller → View) | Interfeys orqali (Presenter → ViewContract) |
| Mantiqni test qilish | UIKit/Android Framework talab qiladi | Platforma bog'liqliklarisiz unit-testlar |
| Hayot aylanishi | Controller ekran bilan yashaydi | Presenter uzoqroq yashashi mumkin (retain) |
| Murakkablik | Minimal | +1 interfeys ekran boshiga |
| Massive Controller | Oddiy muammo | Mantiq Presenter da, View yupqa |
Presenter unit-test namunasi Kotlin da: mock UserView yaratiladi, Presenter ga uzatiladi, loadUser chaqiriladi, showUser to'g'ri ma'lumotlar bilan chaqirilganligi tekshiriladi. Test millisekundlarda bajariladi, emulyator talab qilmaydi. iOS da shunga o'xshash — OCMock yoki protokol-stab UserViewProtocol metod chaqiruvlarini tekshiradi. IT Sectr ning MVP bilan loyihalarida biznes mantiqning unit-testlar bilan qamrovi 85–90% ga yetdi, bu o'xshash MVC loyihalaridan 2–3 baravar yuqori.
MVP qachon MVC dan afzal — barqarorlikka qattiq talablar bilan loyihalarda: bank ilovalari, tibbiy tizimlar, to'lov terminallari. Bu sohalarda xato narxi yuqori va unit-testlar muhim ahamiyatga ega. Post-MVP loyihalarida (mahsulot bozorda, ammo kod bazasi legacy) MVP Massive View Controller dan mantiqni test qilinadigan qatlamga bosqichma-bosqich chiqarish imkonini beradi, arxitekturani to'liq qayta yozmasdan.
MVP ning asosiy kamchiliklari — interfeyslar sonining ko'payishi va obunalarni qo'lda boshqarish. Har bir ekran kamida bitta ViewContract + Presenter talab qiladi, 50 ekran uchun — 50 interfeys va 50 Presenter sinfi. MVVM da ViewModel Presenter ni almashtiradi va reaktiv mexanizmlardan (LiveData, StateFlow, ObservableObject) foydalanadi, bu qo'lda attach/detach va ViewContract interfeyslariga ehtiyojni yo'q qiladi.
RxJava va MVP — Android 2015–2019 da mashhur kombinatsiya. Presenter Repository dan Observable ga obuna bo'ladi, natijani ViewContract orqali ko'rsatadi. Muammo: disposable detachView() da aniq bekor qilinishi kerak, aks holda obuna sizib chiqishi ajratilgan View ni yangilashda crash ga sabab bo'ladi. RxLifecycle va AutoDispose kutubxonalari qisman bekor qilishni avtomatlashtirdi, ammo bog'liqlik qo'shdi. IT Sectr da 2020 yilda MVP+RxJava dan MVVM+Flow ga o'tdik — kod ViewContract ning yo'qolishi hisobiga 25–30% qisqardi.
MVP dan MVVM ga migratsiya — bosqichma-bosqich jarayon. 1) Presenter da ViewContract ni LiveData/StateFlow bilan almashtirish. 2) attach/detach metodlarini olib tashlash — obuna observe() orqali amalga oshadi. 3) Presenter ni ViewModel deb nomlash. 4) ViewModelFactory uchun DI (Hilt/Koin) integratsiyasi. Bitta ekran migratsiyasi 2–4 soat, butun kod bazasi migratsiyasi — 50–100 ekranli loyiha uchun 2–4 hafta davom etadi. Migratsiyadan so'ng ViewContract interfeyslari olib tashlanadi, kod qisqaradi, testlar qoladi.
Zamonaviy ishlanmada MVP — namuna yashaydi, ammo MVVM va MVI dan ortda qoladi. Google rasman yangi loyihalar uchun MVVM ni Jetpack bilan tavsiya qiladi. Apple — MVVM ni SwiftUI bilan. Shunga qaramay, MVP ni bilish legacy kod bilan ishlash uchun majburiy: Google Play da yuzlab Android ilovalari, jumladan yirik banklar, chakana savdo tarmoqlari va transport kompaniyalarining ilovalari hali ham MVP da ishlaydi. MVP ni tushunish MVI va Clean Architecture ni o'zlashtirish uchun asosdir, chunki Presenter Robert Martin terminologiyasida Use Case ning to'g'ridan-to'g'ri ajdodidir.
Tez-tez beriladigan savollar
MVP da Presenter View bilan ViewContract interfeysi orqali o'zaro aloqa qiladi, to'g'ridan-to'g'ri emas. MVC da Controller View ga to'g'ridan-to'g'ri havolaga ega (IBOutlet/findViewById). MVP Presenter ni unit-testlar bilan iOS Simulator yoki Android Emulator siz test qilish imkonini beradi, chunki Presenter UIKit yoki Android Framework ga bog'liq emas. MVC kontrollerni test qilish uchun ilovani ishga tushirishni talab qiladi.
MVP allaqachon shu namunada qurilgan legacy loyihalarda va reaktiv mexanizmlarni (LiveData, StateFlow, Combine) qo'llab-quvvatlamaydigan ilovalarda asoslanadi. Yangi loyihalar uchun Google MVVM ni Jetpack bilan (Android), Apple esa MVVM ni SwiftUI bilan (iOS) tavsiya qiladi. MVP Combine siz toza UIKit dagi loyihalar uchun biznes mantiqni unit-test qilish talabi bilan eng yaxshi tanlov bo'lib qolmoqda.
Android da — retain-fragment (setRetainInstance(true)) yoki Jetpack dan ViewModel ishlatish. Retain-fragment Presenter ni aylantirishda saqlaydi va yangi Activity ga uzatadi. Google ning ViewModel i — retain-fragmentlarsiz aylantirishda holatni avtomatik saqlaydigan zamonaviy alternativa. iOS da — Presenter har viewDidLoad da qayta yaratiladi, lekin alohida koordinator xizmatida kesh saqlanadi.
Minimal 4: ViewContract interfeysi, ViewContract amalga oshirilishi (Activity/Fragment), Presenter, Model (Repository). Dagger/Hilt ishlatilsa, DI moduli qo'shiladi. 50 ekran uchun bu 200+ sinf. MVVM sonni ekran boshiga 1 faylga kamaytiradi (ViewContract kerak emas), MVI State va Intent sinflarini qo'shadi. Sinflar soni — katta loyihalarda MVP ga qarshi asosiy dalil.
Passive View — View mantiqni o'z ichiga olmaydi, Presenter to'liq holat va ma'lumotlarni boshqaradi. Supervising Controller — View o'zi oddiy bog'lashni amalga oshiradi (data binding), Presenter murakkab stsenariylarga aralashadi. Mobil ishlanmada Passive View ustunlik qiladi — maksimal test qilinish va bashorat qilinishni beradi. Supervising Controller veb-freymvorklarda (ASP.NET Web Forms, GWT) qo'llaniladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.
Shuningdek o'qing