MVP (Model–View–Presenter)
[b]Ćwiczenie[/b] Celem ćwiczenia było zapoznanie się z wzorcem projektowym MVP (Model–View–Presenter) w C#. W ramach laboratorium stworzyliśmy aplikację okienkową oraz webową implementującą wzorzec MVP. [b]Wstęp[/b] MVP (Model–View–Presenter) MVP to wzorzec projektowy będący pochodną wzorca MVC. Wzorce te używane są do odseparowania warstwy logiki aplikacji od warstwy prezentacji. W przypadku MVP prezenter pełni rolę pośrednika pomiędzy widokiem, a modelem co było charakterystyczne dla kontrolera w MVC. Widok nie ma bezpośredniego dostępu do modelu w MVP.
[b]Ćwiczenie[/b] Celem ćwiczenia było zapoznanie się z wzorcem projektowym MVP (Model–View–Presenter) w C#. W ramach laboratorium stworzyliśmy aplikację okienkową oraz webową implementującą wzorzec MVP.
[b]Wstęp[/b] MVP (Model–View–Presenter) MVP to wzorzec projektowy będący pochodną wzorca MVC. Wzorce te używane są do odseparowania warstwy logiki aplikacji od warstwy prezentacji.
W przypadku MVP prezenter pełni rolę pośrednika pomiędzy widokiem, a modelem co było charakterystyczne dla kontrolera w MVC. Widok nie ma bezpośredniego dostępu do modelu w MVP. Oprócz tego widok odpowiada za obsługę interakcji użytkownika z aplikacją i reagowanie na zdarzenia od użytkownika.
MVP jest głównie wzorcem projektowy dla interfejsu użytkownika. Jego kluczowym zadaniem jest ułatwienie odseparowania logiki prezentacji tak aby można było przedstawić te same dane w różny sposób (np. aplikacja okienkowa lub internetowa). Opis poszczególnych elementów MVP Model – odpowiada za logikę biznesową aplikacji czyli zarządzanie danymi na których operuje aplikacja. Model może być wielokrotnie wykorzystywany dzięki czemu tylko raz określamy jak aplikacja ma korzystać z danych. Model nie ma bezpośredniego połączenia z widokiem w MVP.
Widok – odpowiada za wyświetlanie w interfejsie użytkownika danych z modelu, przy czym dane te są pobierane poprzez pośrednika jakim jest prezenter. Widok obsługuje także zdarzenia i dane wprowadzane przez użytkownika, a następnie przekazuje je do prezentera.
Prezenter – jego zadaniem jest aktualizowanie modelu i widoku. Prezenter pobiera dane z modelu (może je formatować na różny sposób) a następnie przekazuje do widoku. Działa także w drugą stronę czyli odbiera dane z widoku i aktualizuje model.
[b]Aplikacja w C#[/b] W ramach zajęć przygotowaliśmy projekt podzielony na kilka podprojektów:
- projekt dla modelu
- projekt dla prezentera (zawierający dodatkowo interfejs widoku, który ma implementować widok korzystający z prezentera)
- projekt aplikacji okienkowej
- projekt aplikacji webowej
[b]Podprojekt: Model[/b]
Info: Nasza aplikacja będzie korzystać z modelu, który używa klasy Element. Więcej informacji w komentarzach w kodzie.
Klasa Element: [code=csharp]namespace Model { // Klasa Element będzie przechowywać pola Imie, Nazwisko oraz przedmioty. public class Element { public string Imie { get; set; } public string Nazwisko { get; set; }
// lista przedmiotów
public IList<string> przedmioty;
// metoda zwracająca liste przedmiotów
public IList<string> Przedmioty { get { return przedmioty; } }
// Konstruktor ustawiający domyślne wartości dla pól
internal Element() // internal (pakietowy)
{
Imie = "Jan";
Nazwisko = "Kowalski";
przedmioty = new List<string>();
przedmioty.Add("Komputer");
przedmioty.Add("Telewizor");
}
}
}[/code]
Interfejs IModel: Określamy interfejs naszego modelu.
[code=csharp]namespace Model { // Interfejs IModel public interface IModel { // metoda zwracająca obiekt typu Element Element getElement();
// metoda ustawiająca element
void setElement(Element element);
}
}[/code]
Klasa Model: Nasz model implementuje interfejs IModel. Jak widać korzystamy z klasy Element aby przechowywać informacje o imieniu, nazwisku, przedmiotach.
[code=csharp]namespace Model { // dziedziczymy po interfejsie IModel public class Model : IModel { // prywatne pole typu Element private Element element;
// metoda zwracająca obiekt typu Element
public Element getElement()
{
// jeśli pole element nie ma wartości to tworzymy nowy obiekt typu Element
if (element == null)
element = new Element();
return element;
}
// metoda ustawiająca wartość dla naszego prywatnego pola element
public void setElement(Element element)
{
this.element = element;
}
}
}[/code]
Podprojekt: Presenter W projekcie Presenter dodaliśmy referencje do projektu Model, aby móc korzystać z klasy Model.
Interfejs IView: Musimy określić co musi zawierać nasz widok. W tym celu tworzymy interfejs IView, który będzie implementowany przez aplikację okienkową jak również przez aplikację webową. [code=csharp] namespace View { // interfejs IView // określamy jakie składowe wymaga widok public interface IView { string Imie { get; set; } string Nazwisko { get; set; } IList Przedmioty { set; } } }[/code]
Interfejs IPresenter: Tworzymy interfejs dla prezentera. Musi on zawierać deklaracje wymaganych odpowiednich pól i metod, które będą implementowane przez prezenter.
[code=csharp]namespace Presenter { // interfejs presenter public interface IPresenter { string Imie { get; set; } string Nazwisko { get; set; }
// metoda zwracająca liste przedmiotów
IList<string> Przedmioty { get; }
// metoda zapisująca dane
void SaveDate();
}
}[/code]
Klasa Presenter: Prezenter implementuje interfejs IPresenter. Definiujemy jak mają wyglądać metody do odbierania danych z modelu oraz metody do zapisywania danych w modelu.
[code=csharp]namespace Presenter { // dziedziczymy po IPresenter public class Presenter : IPresenter { // deklarujemy pola dla odpowiednich typów Model.IModel model; Model.Element element; View.IView view;
// Konstruktor przyjmuje obiekt widoku.
// Do obiektu widoku będą zapisywane dane pobrane z modelu przez presenter.
public Presenter(View.IView view)
{
// ustawiamy aktualny obiekt widoku do pola view
this.view = view;
// tworzymy nowy obiekt modelu
model = new Model.Model();
// pobieramy nasze elementy z modelu i wczytujemy do pola element
element = model.getElement();
// ustawiamy właściwości widoku na wartości pobrane wcześniej z modelu
view.Imie = Imie;
view.Nazwisko = Nazwisko;
view.Przedmioty = Przedmioty;
}
public string Imie
{
get
{
// zwraca wartość dla imienia pobraną z modelu
return element.Imie;
}
set
{
// ustawia nową wartość imienia
element.Imie = value;
}
}
public string Nazwisko
{
get
{
return element.Nazwisko;
}
set
{
element.Nazwisko = value;
}
}
public IList<string> Przedmioty
{
// zwraca listę przedmiotów pobraną wcześniej do pola element z modelu
get { return element.Przedmioty; }
}
// metoda odczytuje dane z widoku i przekazuje do modelu
public void SaveDate()
{
this.element.Imie = this.view.Imie;
this.element.Nazwisko = this.view.Nazwisko;
// zapisujemy dane odczytane z widoku do modelu
model.setElement(this.element);
}
}
}[/code]
[b]Czas na praktyczne działanie[/b] MVP świetnie nadaje się do szybkiego tworzenia aplikacji z różnym interfejsem użytkownika, który implementuje nasz widok. Aby sprawdzić czy jest tak w praktyce stworzyliśmy w tym celu dwie aplikacje.
Info: W obu naszych projektach musimy dodać referencje do Presenter. Aplikacja okienkowa: Przygotowaliśmy aplikacje okienkową, która w polach formularza wyświetla dane z modelu.
Klasa Form1:
[code=csharp]namespace WindowsFormsApplication1
{
// Dziedziczymy interfejs IView, a więc musimy przygotować
// odpowiednie pola i metody do obsługi naszego widoku.
public partial class Form1 : Form, View.IView
{
// pole typu IPresenter
Presenter.IPresenter presenter;
public Form1()
{
InitializeComponent();
// Tworzymy nowy obiekt presentera.
// Przekazujemy poprzez this do presentera tę instację klasy Form1,
// która dziedziczy po interfejsie IView zatem konstruktor presentera może ją przyjąć
presenter = new Presenter.Presenter(this);
}
// Implementujemy metody wymagane przez IView
public string Imie
{
get
{
// zwraca wartość pola tbImie z formularza aplikacji
return tbImie.Text;
}
set
{
// ustawiamy wartość pola tbImie w formularzu
tbImie.Text = value;
}
}
public string Nazwisko
{
get
{
return tbNazwisko.Text;
}
set
{
tbNazwisko.Text = value;
}
}
public IList<string> Przedmioty
{
// ustawiamy źródło danych dla lbPrzedmioty
set { lbPrzedmioty.DataSource = value; }
}
}
}[/code]
[b]Aplikacja webowa[/b] Drugi przykład implementacji interfejsu IView zrealizowaliśmy w aplikacji webowej. Dodaliśmy w niej referencje do Presenter.
[b]Podsumowanie[/b] W ramach laboratorium poznaliśmy wzorzec MVP oraz różnice między MVC. Zrealizowaliśmy przykładowy projekt stosując MVP w dwóch różnych aplikacjach implementujących nasz interfejs IView.