Dalam pola MVP haruskah tampilan instantiate objek Model berdasarkan konten UI, atau hanya meneruskan konten ini sebagai parameter ke Presenter?

9

Saya menggunakan pola MVP di aplikasi android yang saya kembangkan.

Saya pada dasarnya memiliki 4 elemen:

  1. AddUserView tempat pengguna baru dapat ditambahkan:
  2. AddUserPresenter
  3. The UserInfo (the pojo)
  4. UserInfoManager (logika bisnis dan manajer penyimpanan)

Pertanyaanku adalah:

Ketika saya menekan tombol "Add" di AddUserView, itu akan mendapatkan konten dari tampilan teks, instantiate UserInfo baru dan berikan ke Presenter. Atau haruskah AddUserView hanya mendapatkan konten textViews dan meneruskannya ke AddUserPresenter, yang pada kenyataannya akan membuat instantiate UserInfo dan meneruskannya ke UserInfoManager?

Terima kasih
sumber

Jawaban:

8

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 UserInfolangsung ke tampilan menggunakan pengendali acara? Perbedaan utama adalah bahwa presenter masih bertanggung jawab atas logika yang menyebabkan UserInfoobjek 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 UserInfodibuat 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 UserInfomungkin secara fisik ada di kelas View, itu tidak pernah dipanggil dari kelas View, hanya dari Presenter.

Tentu saja, jika pembuatan UserInfoakhir 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 ifpernyataan untuk alasan apa pun (bahkan jika itu adalah ifpernyataan tentang keadaan properti widget - memeriksa kotak teks kosong, atau boolean untuk kotak centang), maka itu milik di presenter.

Ben Cottrell
sumber
1
Jawaban bagus @BenCottrell! Tapi saya punya satu lagi :) Apakah praktik yang baik menamai metode presenter onSomethingClicked(), jadi ketika pengguna mengklik "sesuatu", Lihat panggilan presenter.onSomethingClicked()? Atau metode presenter saya harus dinamai sebagai tindakan yang dimaksud, dalam kasus saya addUser()?
Rômulo.Edu
1
@regmoraes Pertanyaan bagus; dan saya pikir Anda telah menyoroti sedikit bau pada kode contoh saya. The Presentertentu saja bertanggung jawab untuk logika UI daripada logika domain, dan disesuaikan khusus untuk View, oleh karena itu konsep yang harus ada adalah konsep UI, sehingga metode bernama onSomethingClicked()memang tepat. Dengan melihat ke belakang, penamaan yang saya pilih dalam contoh saya di atas tidak berbau benar :-).
Ben Cottrell
@ BenCottrell Pertama, terima kasih banyak atas jawaban yang bagus. Saya mengerti, itu sah memiliki GetUserInfometode ini dalam pandangan seperti yang Anda sebutkan (akan dipicu dari presenter) Bagaimana dengan ifkondisi yang mungkin di dalam GetUserInfometode? 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, GetUserInfometode akan memiliki kondisi jika. Dalam skenario GetUserInfoini masih valid?
blackkara
1
@ Blackkara Pertimbangkan memperlakukan UserInfosebagai model-of-the-view (alias "View Model") - Dalam skenario itu saya akan menambahkan booleankeadaan kotak centang dan keadaan kosong / nullable Stringdari kotak teks ke dalam UserInfo. Anda bahkan dapat mempertimbangkan untuk mengubah nama menjadi UserInfoViewModeljika itu membantu untuk berpikir dalam hal POJO menjadi kelas yang tujuan utamanya adalah untuk membiarkan UserInfoPresentermencari tahu informasi tentang kondisi Tampilan.
Ben Cottrell