Menurut deskripsi Martin Fowler tentang MVP ( http://martinfowler.com/eaaDev/uiArchs.html )
Dari bagian Lihat MVC, Fowler mengatakan:
Elemen pertama Potel adalah memperlakukan tampilan sebagai struktur widget, widget yang sesuai dengan kontrol model Forms and Controls dan menghapus pemisahan tampilan / pengontrol. Pandangan MVP adalah struktur dari widget ini. Itu tidak mengandung perilaku apa pun yang menjelaskan bagaimana widget bereaksi terhadap interaksi pengguna .
(Penekanan tebal saya)
Kemudian dari presenter:
Reaksi aktif terhadap tindakan pengguna tinggal di objek presenter terpisah. Penangan dasar untuk gerakan pengguna masih ada di widget, tetapi penangan ini hanya memberikan kontrol kepada presenter .
Presenter kemudian memutuskan bagaimana bereaksi terhadap acara tersebut. Potel membahas interaksi ini terutama dalam hal tindakan pada model, yang dilakukan oleh sistem perintah dan pilihan. Hal yang berguna untuk disoroti di sini adalah pendekatan pengemasan semua suntingan ke model dalam suatu perintah - ini memberikan dasar yang baik untuk menyediakan perilaku undo / redo.
(Sekali lagi, penekanan milikku)
Jadi, sesuai dengan pedoman Fowler, Tampilan Anda tidak boleh bertanggung jawab atas perilaku apa pun sebagai respons terhadap peristiwa tombol; termasuk membuat instance dari UserInfo
. Tanggung jawab memutuskan untuk membuat objek adalah milik metode Presenter yang meneruskan acara UI.
Namun, orang juga dapat berargumen bahwa pengendali event tombol View juga tidak bertanggung jawab untuk meneruskan konten Anda textView
, karena View seharusnya hanya meneruskan peristiwa tombol ke Presenter dan tidak lebih.
Dengan MVP, pandangan umum untuk mengimplementasikan antarmuka yang presenter dapat gunakan untuk mengambil data langsung dari tampilan (sambil memastikan presenter masih agnostik dengan tampilan itu sendiri). Karena UserInfo adalah POJO sederhana, mungkin sah untuk tampilan untuk mengekspos pengambil untuk UserInfo yang Presenter dapat mengambil dari Tampilan melalui antarmuka.
// The view would implement IView
public interface IView {
public UserInfo GetUserInfo();
}
// Presenter
public class AddUserPresenter {
private IView addUserView;
public void SetView(IView view) {
addUserView = view
}
public void onSomethingClicked() {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Apa bedanya dengan meneruskan UserInfo
langsung ke tampilan menggunakan pengendali acara? Perbedaan utama adalah bahwa presenter masih bertanggung jawab atas logika yang menyebabkan UserInfo
objek dibuat. yaitu acara mencapai Presenter sebelum penciptaan UserInfo
, yang memungkinkan Presenter untuk membuat keputusan.
Bayangkan sebuah skenario di mana Anda memiliki logika presenter di mana Anda tidak ingin itu UserInfo
dibuat berdasarkan pada beberapa keadaan dalam tampilan. Misalnya, jika pengguna belum mencentang kotak centang pada tampilan, atau Anda memiliki pemeriksaan validasi terhadap beberapa bidang yang akan ditambahkan ke dalam UserInfo yang gagal - presenter Anda mungkin berisi pemeriksaan tambahan sebelum memanggil GetUserInfo
- yaitu
private boolean IsUsernameValid() {
String username = addUserView.GetUsername();
return (username != null && !username.isEmpty());
}
public void onSomethingClicked() {
if (IsUsernameValid()) {
UserInfo userInfo = addUserView.GetUserInfo();
// etc.
}
}
Logika itu tetap ada di dalam presenter, dan tidak perlu ditambahkan ke dalam view. Jika pandangan bertanggung jawab untuk memanggil GetUserInfo()
maka itu juga akan bertanggung jawab untuk setiap logika seputar penggunaannya; itulah yang ingin dihindari oleh pola MVP.
Jadi, sementara metode yang menciptakan yang UserInfo
mungkin secara fisik ada di kelas View, itu tidak pernah dipanggil dari kelas View, hanya dari Presenter.
Tentu saja, jika pembuatan UserInfo
akhir memerlukan pemeriksaan tambahan terhadap konten widget input pengguna (mis. Konversi string, validasi, dll.), Maka akan lebih baik untuk mengekspos pengambil individu untuk hal-hal tersebut sehingga validasi / konversi string dapat dilakukan Tempatkan di dalam Presenter - dan kemudian presenter menciptakan UserInfo
.
Secara keseluruhan, tujuan utama Anda berkaitan dengan pemisahan antara Presenter / View adalah memastikan bahwa Anda tidak perlu menulis logika dalam tampilan. Jika Anda merasa perlu menambahkan if
pernyataan untuk alasan apa pun (bahkan jika itu adalah if
pernyataan tentang keadaan properti widget - memeriksa kotak teks kosong, atau boolean untuk kotak centang), maka itu milik di presenter.
onSomethingClicked()
, jadi ketika pengguna mengklik "sesuatu", Lihat panggilanpresenter.onSomethingClicked()
? Atau metode presenter saya harus dinamai sebagai tindakan yang dimaksud, dalam kasus sayaaddUser()
?Presenter
tentu saja bertanggung jawab untuk logika UI daripada logika domain, dan disesuaikan khusus untukView
, oleh karena itu konsep yang harus ada adalah konsep UI, sehingga metode bernamaonSomethingClicked()
memang tepat. Dengan melihat ke belakang, penamaan yang saya pilih dalam contoh saya di atas tidak berbau benar :-).GetUserInfo
metode ini dalam pandangan seperti yang Anda sebutkan (akan dipicu dari presenter) Bagaimana denganif
kondisi yang mungkin di dalamGetUserInfo
metode? Mungkin beberapa bidang UserInfo akan ditetapkan melalui reaksi pengguna? Skenario: Mungkin pengguna memilih kotak centang kemudian beberapa komponen baru (mungkin EditText baru) akan terlihat oleh pengguna. Jadi dalam hal ini,GetUserInfo
metode akan memiliki kondisi jika. Dalam skenarioGetUserInfo
ini masih valid?UserInfo
sebagai model-of-the-view (alias "View Model") - Dalam skenario itu saya akan menambahkanboolean
keadaan kotak centang dan keadaan kosong / nullableString
dari kotak teks ke dalamUserInfo
. Anda bahkan dapat mempertimbangkan untuk mengubah nama menjadiUserInfoViewModel
jika itu membantu untuk berpikir dalam hal POJO menjadi kelas yang tujuan utamanya adalah untuk membiarkanUserInfoPresenter
mencari tahu informasi tentang kondisi Tampilan.