Minggu lalu saya membaca beberapa artikel tentang menggunakan WCF, kerangka kerja entitas dan cara mengangkut entitas melintasi batas layanan. Salah satu artikel yang saya temui termasuk proyek demo yang memanfaatkan pola Model View Presenter (MVP).
Setelah menjelajahi proyek demo, saya pikir mungkin menarik untuk menulis artikel tentang pola ini. Mesin pencari favorit Anda akan dengan senang hati memberi Anda sejumlah besar tautan ke artikel lain yang menjelaskan pola ini secara menyeluruh.
Untuk artikel ini saya telah memutuskan untuk menyediakan implementasi konkret dan kurang fokus pada teori di balik pola tersebut.
Ayo gulung ...
Tentu saja diperlukan sedikit teori, jadi mari kita singkirkan.
Seperti yang dapat Anda kurangi dari nama, pola MVP terdiri dari tiga bagian yang berbeda: model, tampilan, dan presenter. Masing -masing bagian ini memainkan peran mereka sendiri dalam membangun pemisahan kekhawatiran antara presentasi, lapisan bisnis dan data akses data.
Model ini bertanggung jawab untuk menangani akses data, presenter berkomunikasi dengan model dan meneruskan data dari dan ke sana. Tampilan menerima data dari presenter dan meneruskan data, tidak pernah berkomunikasi langsung dengan model. Presenter adalah perantara untuk tampilan dan model.
Gambar 1 - Interaksi Pola MVP

Gambar di atas menggambarkan tampilan sebagai menerapkan antarmuka. Lapisan presentasi baik itu aplikasi ASP.NET, WinForms atau WPF perlu menerapkan satu atau lebih antarmuka tampilan. Presenter pada gilirannya berkomunikasi dengan implementasi tampilan melalui antarmuka ini, ia tidak tahu apa -apa tentang implementasi yang sebenarnya itu sendiri.
Ini memberikan kopling longgar dan mencegah kode Anda tergantung pada teknologi yang digunakan untuk lapisan presentasi. Idenya adalah bahwa Anda harus dapat mengganti lapisan ini tanpa memengaruhi logika akses bisnis dan data Anda.
Ini semua mungkin tampak sedikit kabur, tetapi hal -hal harus hilang begitu kita beralih ke titik -titik berikut yang memberikan implementasi aktual dari pola ini. Sebagai contoh, aplikasi ASP.NET akan digunakan.
Tempat yang paling logis untuk memulai adalah model. Karena bertanggung jawab untuk menangani akses data dan penyimpanan, pertama -tama kita perlu membuat penyimpanan data fisik. Untuk ini saya menggunakan SQL Server 2005 Express, membuat database baru yang disebut Southwind dan menambahkan satu tabel berjudul Pelanggan. Tabel memiliki 3 bidang, yaitu:
Itu untuk database. Mari kita nyalakan Visual Studio 2008 dan buat solusi kosong baru bernama Avppattern. Selanjutnya tambahkan pustaka kelas berjudul "Database".
Biasanya saya akan memberikan nama proyek yang mengikuti pola "company.product.library", tetapi demi kesederhanaan, mari kita tetap pendek dan sederhana. Juga hapus file class1.cs autogenerated setelah proyek ditambahkan ke solusi.
Mari kita buat model dari database menggunakan Entity Framework (EF). Jadi pastikan Anda menggunakan Visual Studio 2008 dan memasang Paket Layanan 1 untuk Visual Studio dan .NET Framework 3.5. Anda dapat mengunduh paket layanan di sini.
Tambahkan model data Entity Framework ke pustaka kelas dengan memilih Tambah, Item Baru, Model Data Entitas ADO.NET dari menu konteks proyek di Solution Explorer. Visual Studio sekarang akan menampilkan Wizard Model Data Entitas. Sebutkan model Southwind dan biarkan Visual Studio menghasilkan model untuk Anda. Ketika ditanya objek basis data mana yang ingin Anda sertakan dalam model Anda cukup pilih tabel pelanggan dari node tabel.
Komentar : Jika Anda tidak terbiasa dengan menghasilkan model data dengan kerangka kerja entitas, saya sangat menyarankan video pelatihan ini dari Alex James. Ini menunjukkan kepada Anda cara membangun model data entitas sederhana dari awal.
Gambar 2 menunjukkan model data entitas yang dihasilkan. Model tidak bisa lebih sederhana dari ini. Ini dilakukan dengan sengaja untuk menjaga hal -hal sesederhana mungkin dan untuk tetap fokus pada pola MVP.
Gambar 2 - Model Data Entitas

Pastikan untuk mengganti nama entitas dan entitas Anda menjadi nama yang sesuai setelah model data dihasilkan. Aturan praktisnya adalah menggunakan kata benda tunggal untuk entitas dan jamak untuk entitas. Jadi dalam hal ini EntityType kami harus dinamai pelanggan dan pelanggan EntitySet. Nama untuk EntityType sudah OK karena mewarisi itu dari tabel pelanggan, jadi pilih saja EntityType pelanggan dan sesuaikan properti Name Set Entity Set.
Gambar 3 - Nama Set Entitas

Kerangka kerja entitas akan secara otomatis menghasilkan kelas parsial untuk tabel pelanggan. Anda dapat memilih untuk memperpanjang kelas pelanggan sebagian ini jika Anda mau. Untuk mencegah penambahan khusus Anda dari dihapus saat meregenerasi model, masukkan kode ini ke dalam file kelas yang terpisah. Ini simular untuk bekerja dengan set data yang sangat diketik. Namun, untuk artikel ini tidak diperlukan.
Gambar 4 - Penjelajah Solusi

Sekarang modelnya ada di tempat, mari kita tambahkan lapisan bisnis di atasnya di mana kita dapat menentukan logika bisnis khusus kita. Demi kesederhanaan saya akan menjaga jumlah kode terbatas di lapisan ini.
Perhatikan bahwa lapisan-lapisan ini hanya menegakkan pemisahan logis (N-layer), bukan yang fisik (n-tier). Semua lapisan berada di mesin yang sama, meskipun Anda pasti bisa memilih untuk menghapus mereka di beberapa mesin / tingkatan dan membuat aplikasi yang benar-benar terdistribusi atau N-tier.
Untuk mengatur lapisan bisnis, tambahkan pustaka kelas baru ke solusi dan sebut saja bisnis. Berikutnya ganti nama file class.cs default ke customermanager.cs. Juga tambahkan referensi ke basis data pustaka kelas yang dibuat sebelumnya dan ke perakitan System.data.entity.
Listing 1 Menampilkan kelas CustomerManager yang berisi beberapa logika bisnis untuk bekerja dengan entitas pelanggan dari Entity Data Model (EDM). Kode ini cukup jelas.
Daftar 1 - Kelas CustomerManager
using System . Collections . Generic ;
using System . Linq ;
using Database ;
namespace Business
{
public class CustomerManager
{
private readonly SouthwindEntities context ;
#region Constructor(s)
public CustomerManager ( )
{
context = new SouthwindEntities ( ) ;
}
#endregion
#region Methods
// Retrieve a generic list of Customer entities.
// This method will return all the customers found in the Customer table.
public List < Customer > GetCustomers ( )
{
var q = from c in context . Customers
select c ;
return q . ToList ( ) ;
}
#endregion
}
}Gambar 5 - Solusi yang diperbarui

Komentar : Menyiapkan aplikasi N-tier akan mencakup memperkenalkan lapisan layanan yang diminta oleh lapisan presentasi. Lapisan layanan kemudian menggunakan objek bisnis yang ditemukan di lapisan bisnis. Tidak ada hubungan langsung antara presentasi dan lapisan bisnis lagi, lapisan layanan bertindak sebagai perantara. Dalam artikel mendatang saya akan membahas ini dengan menunjukkan cara mengangkut entitas EF melintasi batas layanan.
Lapisan bisnis hanya berisi satu metode yang berguna, yaitu "Daftar GetCustomers ()". Presenter dalam pola MVP akan memanggil metode ini pada objek bisnis CustomerManager untuk mengirimkan data ke tampilan.
Contoh aplikasi hanya menunjukkan daftar pelanggan menggunakan pola MVP. Ini mungkin sedikit berlebihan, tetapi tetap sesederhana mungkin dengan desain. Tujuan utama dari ini "Hello World!" Jenis aplikasi adalah untuk mendapatkan ide melintasi cara menerapkan pola ini. Fungsionalitas aktual yang ditawarkan oleh aplikasi tidak begitu penting.
Implementasi tampilan aktual (halaman ASPX, WinForms, WPF ... dll.) Akan perlu menerapkan antarmuka tampilan. Implementasi tampilan perlu membuat instance presenter dan meneruskan dirinya sebagai parameter dalam konstruktornya. Konstruktor presenter memiliki satu parameter yang merupakan jenis antarmuka tampilan.
Listing 2 mencantumkan antarmuka IVIEW yang akan kami terapkan segera di halaman ASP.NET ASPX. Ini memiliki satu acara bernama Persiapan. Acara Persiapan Persiapan menggunakan delegasi yang tanda tangannya menetapkan bahwa itu tidak mengembalikan apa pun dan tidak mengambil parameter.
Pandangan seharusnya hanya menaikkan "peristiwa kosong" semacam ini untuk menandakan kepada presenter bahwa beberapa tindakan harus dilakukan. Tindakan dalam kasus ini menandakan bahwa presenter harus menyegarkan daftar pelanggan yang dipertahankan oleh implementasi tampilan. Presenter dapat mengakses daftar pelanggan ini melalui properti pelanggan ilist yang dinyatakan sebagai bagian dari antarmuka.
Listing 2 - Lihat Antarmuka
public delegate void VoidEventHandler ( ) ;
public interface IView
{
event VoidEventHandler PrepareView ;
IList < Customer > Customers { set ; }
}Untuk menambahkan antarmuka tampilan ke proyek Anda terlebih dahulu menambahkan proyek perpustakaan kelas baru ke solusi yang disebut presentasi. Selanjutnya tambahkan antarmuka baru dan salin dan tempel kode yang ditampilkan dalam daftar di atas. Perpustakaan Kode Presentasi juga akan berisi presenter dan antarmuka yang mereka terapkan.
Saya memisahkan antarmuka tampilan dan presenter di pustaka kode terpisah sehingga Anda dapat dengan mudah membagikannya di antara beberapa "kerangka kerja tampilan" seperti ASP.NET, WinForms, WPF ... dll. Gambar 6 menunjukkan bagaimana saya memilih untuk mengatur perpustakaan kode ini.
Gambar 6 - Solusi yang diperbarui

Jangan lupa untuk menambahkan referensi ke basis data dan proyek bisnis dan System.Data.entity Assembly.
Untuk bagian akhir dari pola MVP kita perlu memberikan presenter. Kelas PelangganPresenter yang ditampilkan dalam Listing 3 mengambil referensi ke implementasi IVIEW di konstruktornya. Dengan cara ini dapat berkomunikasi dengan pandangan tanpa benar -benar mengetahui apa pun tentang implementasi yang sebenarnya. Kopling longgar inilah yang membuat pola MVP begitu cocok untuk "kerangka kerja tampilan" yang berbeda.
Juga di konstruktor semua peristiwa antarmuka tampilan terhubung ke penangan acara. Dalam hal ini hanya ada satu peristiwa. Acara Persiapan Persiapan dihubungkan ke penangan acara View_Prepareview. Ini pada gilirannya memanggil metode pribadi presenter GetCustomers () yang mengembalikan koleksi pelanggan "segar" dan menugaskannya ke koleksi pelanggan yang dikelola oleh implementasi tampilan.
Daftar 3 - Kelas Pelanggan
public class CustomersPresenter : ICustomersPresenter
{
#region Fields
private readonly IView view ;
#endregion
#region Constructor(s)
public CustomersPresenter ( IView view )
{
// Save a reference to the view
this . view = view ;
// Hook up an event handler for the events of the view
view . PrepareView += view_PrepareView ;
}
#endregion
#region Private methods
private List < Customer > GetCustomers ( )
{
return new CustomerManager ( ) . GetCustomers ( ) ;
}
#endregion
#region ICustomersPresenter Members
public virtual void view_PrepareView ( )
{
view . Customers = GetCustomers ( ) ;
}
#endregion
}Presenter di atas juga mengimplementasikan antarmuka. Dalam kode sumber sampel antarmuka ini dibiarkan kosong. Saya hanya meletakkannya di sana untuk tujuan ilustrasi. Anda dapat menyempurnakan antarmuka ini jika Anda menginginkannya. Anda mungkin membutuhkannya untuk kerangka pengujian unit favorit Anda untuk mengejek presenter misalnya.
Jadi halaman tampilan atau ASPX dalam kasus kami hanya perlu mengimplementasikan antarmuka tampilan dan memicu acara persiapan untuk menerima daftar pelanggan yang diperbarui dari presenter. Tampilan itu sendiri tidak berkomunikasi dengan database atau lapisan bisnis secara langsung. Presenter menangani komunikasi dengan lapisan bisnis yang mengambil data dengan membahas model (atau lapisan akses data jika Anda mau).
Untuk menyelesaikan artikel ini, mari kita lihat bagaimana semua ini bersatu dalam proyek demo ASP.NET. Tambahkan proyek baru menggunakan Template Proyek Aplikasi Web ASP.NET ke solusi. Tambahkan referensi ke proyek presentasi dan basis data dan perakitan System.data.entity.
Tambahkan GridView bernama "GridView1" dan tombol bernama "Btnrefresh" ke halaman default.aspx. Tambahkan kode dalam daftar 4 ke kode di balik halaman.
Daftar 4 - Kode Default.aspx di belakang
public partial class _Default : System . Web . UI . Page , IView
{
private CustomersPresenter presenter ;
protected override void OnInit ( EventArgs e )
{
presenter = new CustomersPresenter ( this ) ;
}
protected void Page_Load ( object sender , EventArgs e )
{
if ( ! IsPostBack )
{
PrepareView ( ) ;
}
}
protected void btnRefresh_Click ( object sender , EventArgs e )
{
PrepareView ( ) ;
}
#region IView Members
public event VoidEventHandler PrepareView ;
public IList < Database . Customer > Customers
{
set
{
GridView1 . DataSource = value ;
GridView1 . DataBind ( ) ;
}
}
#endregion
}Semua kode di balik halaman ASPX adalah mengimplementasikan antarmuka IView, membuat presenter dan lulus implementasi IVIEW, menjadi dirinya sendiri, ke dalam konstruktornya. Maka semua yang tersisa hanyalah memicu acara persiapan () dari antarmuka iview pada waktu yang tepat.
Selama pembuatan presenter, seorang penangan acara secara otomatis ditugaskan untuk acara ini yang memastikan bahwa ketika dipicu presenter tahu cara memperbarui koleksi pelanggan yang dikelola oleh halaman. Halaman itu sendiri tidak tahu dari mana data ini berasal atau bagaimana itu diambil. The Dumber a View, semakin baik.
Saat melihat halaman ini di browser ini adalah hasilnya:
Gambar 7 - Demo Situs Web ASP.NET

Komentar : Jangan lupa untuk menambahkan ConnectionString yang diperlukan oleh Kerangka Entitas ke file konfigurasi Web.config. Anda dapat menemukan ConnectionString di file App.config dari proyek Perpustakaan Kelas Database. Itu dimasukkan di sana secara otomatis ketika Visual Studio menghasilkan model data entitas.
Tentu saja string koneksi yang disediakan dalam kode sumber sampel tidak akan berfungsi di komputer Anda karena mereka dibangun terhadap database lokal saya. Jadi pastikan untuk menyesuaikannya.
Gambar 8 - Solusi yang diperbarui

Sebagai langkah terakhir dari artikel ini, mari kita buat tampilan menggunakan aplikasi Windows Forms hanya untuk menunjukkan betapa fleksibelnya pola MVP sebenarnya. Langkah -langkah untuk melakukan ini hampir identik dengan contoh sebelumnya dalam membuat situs web ASP.NET. Tambahkan aplikasi Windows Forms baru ke solusi Anda dan tambahkan referensi ke proyek basis data dan presentasi dan perakitan System.data.entity.
Selanjutnya tambahkan DataGridView dan kontrol tombol ke formulir. Kode untuk formulir ditampilkan dalam daftar di bawah ini. Ini hampir identik dengan halaman default.aspx. Juga jangan lupa untuk menambahkan string koneksi Entity Framework ke file konfigurasi app.config.
Daftar 5 - Kode Form1.CS
using System ;
using System . Windows . Forms ;
using Presentation . Presenters ;
using Presentation . ViewInterfaces ;
namespace WindowsFormsApplication
{
public partial class Form1 : Form , IView
{
private CustomersPresenter presenter ;
public Form1 ( )
{
InitializeComponent ( ) ;
presenter = new CustomersPresenter ( this ) ;
}
private void Form1_Load ( object sender , EventArgs e )
{
PrepareView ( ) ;
}
private void btnRefresh_Click ( object sender , EventArgs e )
{
PrepareView ( ) ;
}
#region IView Members
public event VoidEventHandler PrepareView ;
public System . Collections . Generic . IList < Database . Customer > Customers
{
set
{
dataGridView1 . DataSource = value ;
}
}
#endregion
}
}Voila, kami akhirnya selesai. Perhatikan bahwa meskipun contoh ASP.NET dan WinForms hampir identik dalam kode, ini mungkin tidak terjadi dalam aplikasi yang lebih kompleks. Jenis interaksi dalam dua jenis antarmuka pengguna ini sangat berbeda dan muncul dengan presenter yang dapat Anda gunakan dalam semua situasi mungkin bukan potongan yang jelas.
Gambar 9 - Demo Aplikasi Windows Forms

Gambar 10 - Solusi yang diperbarui

Untuk artikel ini interpretasi klasik dari pola MVP digunakan dan ditunjukkan dengan mengimplementasikannya solusi ASP.NET. Pola MVP asli dianggap "pensiunan" sejak Martin Fowler mengumumkannya. Pola dapat dibagi menjadi dua kamp sekarang, menjadi:
Baca artikel Microsoft Patterns & Practices ini untuk informasi lebih lanjut.
Saya menulis artikel ini untuk menyediakan implementasi konkret dari pola MVP saat saya menjelajahinya pada saat itu. Namun mungkin bijaksana untuk menjauhi dan menunggu sampai Microsoft merilis kerangka kerja ASP.NET MVC. Bagi mereka yang ingin meniru kerangka kerja model-view-controller (MVC) sekarang saya sarankan membaca artikel ini dengan Microsoft Patterns & Practices.
Catatan : Pola MVP adalah turunan dari Model View Controller Pattern (MVC). Pada saat penulisan ini Microsoft saat ini sibuk mengembangkan kerangka kerja ASP.NET MVC. Saat memetakan arsitektur untuk proyek situs web baru, saya sarankan untuk memeriksa kerangka kerja ini.
Perbedaan utama antara pola MVP dan MVC dapat ditentukan oleh siapa yang bertanggung jawab untuk menangani input pengguna seperti keyboard dan acara MOUE. Dalam pola MVP GUI itu sendiri bertanggung jawab dan perlu mendelegasikannya kepada presenter melalui peristiwa. Dalam pola MVC pengontrol bertanggung jawab untuk menangani peristiwa ini.