MVP — nedir, iOS ve Android'de Model-View-Presenter deseni

Yazar: IT Sectr Yayınlanma: 2026-02-16 Okuma süresi: 10 dk

MVP (Model-View-Presenter) — Presenter'ın ViewContract arayüzü aracılığıyla Model ve View arasında aracı görevi gördüğü mimari bir desendir. Controller'ın View'i UIKit aracılığıyla doğrudan yönettiği MVC'nin aksine, Presenter çerçeveye bağlı değildir — soyutlama yoluyla çalışır, bu da onu Android SDK veya UIKit olmadan test edilebilir kılar. MVP, Jetpack'ten önce Android geliştirmede yaygın olarak kullanılır ve eski projeler için geçerliliğini korur. Daha fazlası için Martin Fowler'ın makalesine bakın.

Ana Noktalar

  • MVP — üç bileşen: Model (veri), View (arayüz), Presenter (mantık ve durum)
  • ViewContract — Presenter'ın View ile iletişim kurduğu arayüz, test edilebilirliği sağlar
  • Presenter — tüm iş mantığını içerir, Android/iOS platform sınıflarına bağlı değildir
  • Passive View — View maksimum derecede pasiftir, yalnızca Presenter komutlarıyla veri görüntüler
  • MVP vs MVC — Presenter birim testleriyle test edilir, MVC'de Controller UIKit/Android Framework'e bağlıdır

MVP Nedir: Model-View-Presenter deseninin özü

MVP (Model-View-Presenter) — Martin Fowler tarafından 2000'lerin başında kullanıcı arayüzünün test edilebilirliğini geliştirmek için MVC'nin evrimi olarak önerilen mimari bir desendir. Model verileri ve iş mantığını yönetir, View işleme ve kullanıcı girişi işlemeden sorumludur, Presenter View'den olayları alan, Model'den veri alan ve görüntüleme için durumu oluşturan merkezi bileşendir.

MVP ve MVC arasındaki temel fark — Presenter'ın View'e doğrudan bir referansı yoktur. Bunun yerine, Presenter ViewContract arayüzü aracılığıyla View ile etkileşime girer. View bu arayüzü uygular ve kendisini Presenter'a iletir. Bu, UIKit (iOS) veya Android Framework'e olan bağımlılığı kırar — Presenter, ViewContract'in mock uygulamasıyla izole olarak test edilebilir. MVC'de UIViewController denetleyicisi doğrudan UILabel'i günceller, MVP'de Presenter view.showName(name) çağırır ve View nasıl görüntüleneceğine karar verir.

BileşenSorumlulukTest Edilebilirlik
ModelVeri, iş mantığı, ağ çağrılarıBirim testleri (UI'dan bağımsız)
ViewUI işleme, Presenter'a olay iletmeArayüz aracılığıyla mock uygulama
Presenterİş mantığı, durum yönetimi, navigasyonBirim testleri (ViewContract mock ile)

Tek Sorumluluk İlkesi MVP'de MVC'den daha sıkı takip edilir: View yalnızca işlemeden, Model verilerden, Presenter mantık ve koordinasyondan sorumludur. Gerçek projelerde Presenter ekran kodunun %40–60'ını, View %20–30'unu, Model %20–30'unu kaplar. Bu dağılım, Android öykünücüsü veya iOS simülatörü başlatmadan temel iş mantığını test etmeye olanak tanır.

Android'de MVP: Presenter, ViewContract ve Activity

Android'de MVP, ViewContract'i uygulayan Activity veya Fragment'i View olarak kullanır — veri görüntüleme yöntemlerine sahip bir arayüz. Presenter Activity'de oluşturulur, View'i kendisine bağlar ve veri yüklemeyi yönetir. Ekran döndüğünde Activity yeniden oluşturulur — Presenter, bir retain fragment veya harici depolama aracılığıyla korunabilir, bu da saf MVC'nin karakteristik durum kaybı sorununu çözer.

kotlin
// ViewContract — Presenter'ı View'e bağlamak için arayüz
interface UserView {
    fun showLoading()
    fun hideLoading()
    fun showUser(user: User)
    fun showError(message: String)
}

// Presenter — test edilebilir mantık katmanı
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 ?: "Unknown error")
            }
        }
    }
}

// View (Activity) arayüzü uygular
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'yı güncelle */ }
    override fun showLoading() { /* ProgressBar'ı göster */ }
    override fun hideLoading() { /* ProgressBar'ı gizle */ }
    override fun showError(message: String) { /* Snackbar'ı göster */ }
}

Yaşam döngüsü yönetimi — Android'de MVP'nin temel bir sorunudur. Ekran döndürüldüğünde Activity yok edilir ve presenter.attachView() onCreate()'de yeniden çağrılır. Veri yükleme eşzamansızsa (RxJava, coroutines), tamamlandığında View ayrılmış olabilir. Çözüm — detachView()'de abonelikleri iptal etmek veya Support Library'den Loader kullanmak (Jetpack'siz projeler için). IT Sectr'de ticari projelerde yıllarca MVP + RxJava kombinasyonunu kullandık — desen stabildir ancak abonelik yönetiminde disiplin gerektirir.

Retain fragment'lar — ekran döndürüldüğünde Presenter'ı koruma mekanizması. UI'sız fragment (setRetainInstance(true)) Activity'den daha uzun yaşar ve Presenter'a bir referans tutar. Activity yeniden oluşturulduğunda, fragment aynı Presenter'ı yeni Activity'ye iletir. Retain fragment'lar AndroidX'ten beri kullanımdan kaldırılmıştır, ancak pre-Jetpack benzerleri (Fragment.setRetainInstance) eski projelerde hâlâ çalışır. Modern geliştirmede Google, retain fragment'lar yerine ViewModel'i önerir.

iOS'te MVP: Presenter ve View Protocol

iOS'te MVP bir View protokolü aracılığıyla oluşturulur. UIViewController protokolü uygular, Presenter UIKit'i içe aktarmaz ve tamamen test edilebilir. UIViewController'ın kendisinin mantık ve doğrudan IBOutlet bağlantıları içerdiği Apple MVC'nin aksine, Presenter durumu yönetir ve protokol yöntemleri aracılığıyla View'e komut verir. View karar vermez — Presenter'ın komutlarını yürütür: showUser, showLoading, navigateToProfile.

swift
import Foundation

// View Protocol — Presenter için soyutlama
protocol UserViewProtocol: AnyObject {
    func showLoading()
    func hideLoading()
    func display(user: User)
    func displayError(message: String)
}

// Presenter — UIKit'siz saf mantık
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) protokolü uygular
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
    }
    // ... protokolün kalan yöntemleri
}

Weak reference — iOS MVP'de View'e zayıf referans zorunludur. Bir UIViewController yok edilebilir (navigation stack'ten pop) ve Presenter'daki closure'ı bir retain cycle oluşturur. Zayıf referans (weak var), Presenter'daki eşzamansız işlemlerden bağımsız olarak View'in ekrandan ayrıldığında serbest bırakılmasını sağlar. Android'de benzer bir sorun detachView() ile çözülür — onDestroy()'de çağırmak View'e olan referansı geçersiz kılar.

Passive View vs Supervising Controller — Martin Fowler'ın iki MVP çeşidi. Passive View: View mantık içermez, Presenter durumu tamamen yönetir. Supervising Controller: View'in kendisi basit veri bağlama (örneğin data binding) yapar, Presenter yalnızca karmaşık senaryolarda müdahale eder. Mobil geliştirmede Passive View daha sık kullanılır — maksimum test edilebilirlik ve ekran durumunun öngörülebilirliğini sağlar.

MVP ve MVC arasındaki farklar ve test avantajları

Temel fark MVP ve MVC arasında View ile iletişim şeklidir. MVC'de Controller'ın View'e (UIViewController.IBOutlets, Activity.findViewById) doğrudan bir referansı vardır. MVP'de Presenter, ViewContract arayüzü aracılığıyla View ile etkileşime girer. Bu fark, test edilebilirliği temelden değiştirir: ViewContract'i uygulayan bir mock nesnesi, uygulamayı, öykünücüyü veya UI çerçevesini başlatmadan Presenter'ın mantığını test etmeye olanak tanır.

KriterMVCMVP
View bağlantısıDoğrudan (Controller → View)Arayüz aracılığıyla (Presenter → ViewContract)
Mantık testiUIKit/Android Framework gerektirirPlatform bağımlılığı olmadan birim testleri
Yaşam döngüsüController ekranla birlikte yaşarPresenter daha uzun yaşayabilir (retain)
KarmaşıklıkMinimumEkran başına +1 arayüz
Massive ControllerTipik sorunMantık Presenter'da, View ince

Presenter birim testi örneği Kotlin'de: bir mock UserView oluşturulur, Presenter'a iletilir, loadUser çağrılır, showUser'ın doğru verilerle çağrıldığı kontrol edilir. Test milisaniyeler içinde yürütülür, öykünücü gerekmez. iOS'te benzer şekilde — OCMock veya protokol saplaması UserViewProtocol yöntem çağrılarını doğrular. IT Sectr'ın MVP'li projelerinde iş mantığı birim test kapsamı %85–90'a ulaştı, bu benzer MVC projelerinden 2–3 kat daha yüksektir.

MVP'nin MVC'ye tercih edildiği durumlar — katı kararlılık gereksinimleri olan projeler: bankacılık uygulamaları, tıbbi sistemler, ödeme terminalleri. Bu alanlarda hata maliyeti yüksektir ve birim testler kritiktir. MVP sonrası projelerde (ürün zaten piyasadayken ancak kod tabanı eskiyken), MVP tam bir mimari yeniden yazım olmadan Massive View Controller'dan test edilebilir katmana mantığı aşamalı olarak çıkarmaya olanak tanır.

MVP'nin sınırlamaları ve MVVM'ye geçiş

MVP'nin ana dezavantajları — arayüz sayısının artması ve manuel abonelik yönetimi. Her ekran en az bir ViewContract + Presenter gerektirir, 50 ekran için — 50 arayüz ve 50 Presenter sınıfı. MVVM'de ViewModel, Presenter'ın yerini alır ve reaktif mekanizmalar (LiveData, StateFlow, ObservableObject) kullanır, böylece manuel attach/detach ve ViewContract arayüzlerine olan ihtiyacı ortadan kaldırır.

RxJava ve MVP — Android 2015–2019'da popüler bir kombinasyon. Presenter, Repository'den bir Observable'a abone olur, sonucu ViewContract aracılığıyla gösterir. Sorun: disposable'ın detachView()'de açıkça iptal edilmesi gerekir, aksi halde abonelik sızıntısı ayrılmış bir View güncellenirken çökmeye neden olur. RxLifecycle ve AutoDispose kütüphaneleri abonelik iptalini kısmen otomatikleştirdi ancak bağımlılıklar ekledi. IT Sectr'de 2020'de MVP+RxJava'dan MVVM+Flow'a geçtik — ViewContract'in ortadan kalkmasıyla kod %25–30 kısaldı.

MVP'den MVVM'ye geçiş — aşamalı bir süreçtir. 1) Presenter'daki ViewContract'i LiveData/StateFlow ile değiştirin. 2) attach/detach yöntemlerini kaldırın — abonelik observe() aracılığıyla yapılır. 3) Presenter'ı ViewModel olarak yeniden adlandırın. 4) ViewModelFactory için DI (Hilt/Koin) entegre edin. Bir ekranın geçişi 2–4 saat sürer, tüm kod tabanının — 50–100 ekranlı bir proje için 2–4 hafta. Geçişten sonra ViewContract arayüzleri kaldırılır, kod küçülür, testler kalır.

Modern geliştirmede MVP — desen yaşıyor ancak MVVM ve MVI'ye yerini bırakıyor. Google resmi olarak yeni projeler için Jetpack ile MVVM'yi öneriyor. Apple — SwiftUI ile MVVM'yi. Ancak, eski kodla çalışmak için MVP bilgisi zorunludur: Google Play'deki yüzlerce Android uygulaması hâlâ MVP ile çalışır, büyük bankaların, perakendecilerin ve ulaşım şirketlerinin uygulamaları dahil. MVP'yi anlamak, MVI ve Clean Architecture'da ustalaşmanın temelidir, çünkü Presenter, Robert Martin'in terimleriyle Use Case'in doğrudan öncülüdür.

Sıkça Sorulan Sorular

MVP, MVC'den nasıl farklıdır?

MVP'de Presenter, ViewContract arayüzü aracılığıyla View ile etkileşime girer, doğrudan değil. MVC'de Controller'ın IBOutlet/findViewById aracılığıyla View'e doğrudan referansı vardır. MVP, Presenter UIKit veya Android Framework'e bağlı olmadığı için iOS Simulator veya Android Emulator olmadan birim testlerle Presenter'ı test etmeye olanak tanır. MVC, denetleyiciyi test etmek için uygulamanın başlatılmasını gerektirir.

MVVM yerine MVP ne zaman kullanılmalı?

MVP, halihazırda bu desen üzerine inşa edilmiş eski projelerde ve reaktif mekanizmaları (LiveData, StateFlow, Combine) desteklemeyen uygulamalarda haklıdır. Yeni projeler için Google Jetpack ile MVVM'yi (Android) ve Apple SwiftUI ile MVVM'yi (iOS) önerir. MVP, iş mantığı birim testi gerektiğinde Combine olmadan saf UIKit projeleri için en iyi seçim olmaya devam eder.

Ekran döndürüldüğünde Presenter kaybı sorunu nasıl çözülür?

Android'de — bir retain fragment (setRetainInstance(true)) veya Jetpack'ten ViewModel kullanın. Retain fragment döndürme sırasında Presenter'ı saklar ve yeni Activity'ye iletir. Google'ın ViewModel'i, retain fragment'lar olmadan döndürme sırasında durumu otomatik olarak koruyan modern bir alternatiftir. iOS'te — Presenter her viewDidLoad'da yeniden oluşturulur ancak ayrı bir koordinatör hizmetinde önbelleğe alınır.

MVP'de bir ekran için kaç sınıf gerekir?

En az 4: ViewContract arayüzü, ViewContract uygulaması (Activity/Fragment), Presenter, Model (Repository). Dagger/Hilt kullanılıyorsa bir DI modülü eklenir. 50 ekran için 200+ sınıf. MVVM, ekran başına 1 dosya azaltır (ViewContract gerekmez), MVI State ve Intent sınıfları ekler. Sınıf sayısı, büyük projelerde MVP'ye karşı ana argümandır.

MVP'de Passive View ve Supervising Controller arasındaki fark nedir?

Passive View — View mantık içermez, Presenter durumu ve verileri tamamen yönetir. Supervising Controller — View'in kendisi basit bağlama (data binding) yapar, Presenter yalnızca karmaşık senaryolarda müdahale eder. Mobil geliştirmede Passive View baskındır — maksimum test edilebilirlik ve öngörülebilirlik sağlar. Supervising Controller web çerçevelerinde (ASP.NET Web Forms, GWT) kullanılır.

Özet

  • MVP (Model-View-Presenter) — ViewContract arayüzü aracılığıyla test edilebilir Presenter katmanına sahip MVC'nin evrimi
  • ViewContract — View'i Presenter'dan soyutlayan arayüz, mock testine olanak tanır
  • Passive View — pasif View ile mobil geliştirmede baskın MVP çeşidi
  • Presenter — iş mantığını içerir, UIKit veya Android Framework'e bağlı değildir
  • MVP vs MVC — MVP test sorununu çözer ancak ekran başına 1 arayüz ekler
  • Android retain fragment'lar — Jetpack ViewModel'den önce ekran döndürmede Presenter'ı koruma
  • MVVM'ye geçiş — ViewContract'i LiveData/StateFlow ile değiştirmek kodu %25–30 azaltır

Anahtar teslim bir mobil uygulama geliştireceğiz

IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.

Projeyi tartış

Ayrıca okuyun