Projektowanie Graficznych Interfejsów...

49
1 Projektowanie Graficznych Interfejsów Użytkownika Robert Szmurło

Transcript of Projektowanie Graficznych Interfejsów...

Page 1: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

1

Projektowanie Graficznych Interfejsów Użytkownika

Robert Szmurło

Page 2: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

2

Wzorce WebModel View Controller

Page Controller – każda strona ma własny

Front Controller – jeden uniwersalny,

Interpretujący komendy.

Template View

Page 3: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

3

Wzorce projektowe Web

Page Cache

Page Controller

MVC

Front Controller

Intercepting Filter

Projekt

ImplementacjaPache Cachew ASP.NET

ImplementacjaPage Controllerw ASP.NET

ImplementacjaMVCw ASP.NET

ImplementacjaFront Controllerw ASP.NET

ImplementacjaIntercepting Filterw ASP.NET

Implementacja

Na podstawie: Enterprise Solution Patterns Using Microsoft .NET

Page 4: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

4

MVC

cd Struktura Modelu MVC

Model

Kontroler

Widok

Page 5: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

5

Model pasywny MVC (wg .NET)

cd MVC Pasywny

:Kontroler :Model :Widok

Uzytkownik

obsłużZdarzenie

uaktualn i j

wyświetlDane

podajStan

Page 6: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

6

Model aktywny MVC (wg .NET)

Tylko poinformuj, żezaszła jakaś zmiana!

sd MVC.Active

:Model :Widok

Źródło zmian

obsłużZdarzenie()

powiadom()

uaktualnij ()

dajAktualneWartości()

dane()

Page 7: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

7

Model aktywny - obserwator

cd MVC Obserwator

«interface»Obserwator

+ uaktualn i j() : vo id

Model

Kontroler

Widok«real ize»

«rea l ize»

Rozwiązanie problemu zależności Modelu od reszty modułów za pomocą ogólnego interfejsu obserwatora, który jest realizowany przez pozostałe moduły.

Page 8: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

8

Wady i zalety MVCZalety

– Wiele widoków – różne strony aplikacji webowej mogą prezentować dane z tych samych obiektów modelu,

– Zmiany – łatwiejsze zmiany zmieniającego się dużo częściej od modelu interfejsu

– Zależność od platformy – Kod interfejsu użytkownika często ściśle zależy od specyficznych cech platformy..

Wady– Nadmierne skomplikowanie – dodatkowe warstwy oraz rygor niezależności;

intensywne wykorzystanie programowania zdarzeniowego, które jest trudne w debugowaniu.

– Koszt częstych uaktualnień/powiadomień – uaktualnienie widoku zabiera formularzowi jakiś czas; gdy model często zmienia swój stan, może zablokować ekran, a przez to uniemożliwić pracę dla użytkownika.

Page 9: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

9

Refaktoryzacja SP ==> MVCPrześledzimy proces refaktoryzacji z z wzorca:

– Single Page Controller

do wzorca:– MVC

Aplikacja do wyświetlania albumów muzycznych.– Dane znajdują się w bazie (u nas plik Accessa: baza.mdb)

1. Za pomocąmenu rozwijalnego z

[listą albumów]użytkownik wybiera

album.

2. Użytkownik wybiera

opcję Pokaż.

3. System wyświetla[tabelę z utworami]

na [wybranym albumie].

SinglePage

WidokKontroler+Model

WidokModel

Kontroler

Refaktoryzacja 1 Refaktoryzacja 2

Page 10: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

10

Na początek wszystko na stronie 1/2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><%@ Import Namespace="System.Data" %><%@ Import Namespace="System.Data.OleDb" %>

<html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>Album płytowy</title> <script language="c#" runat="server"> void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack) { String selectCmd = "select * from Plyty"; OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source='c:\\Projekty\\svn\\pgui\\LN_2007\\NET\\baza.mdb'"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd,myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "plyty"); recordingSelect.DataSource = ds; recordingSelect.DataTextField = "tytul"; recordingSelect.DataValueField = "id"; recordingSelect.DataBind(); } } void SubmitBtn_Click(Object sender, EventArgs e) { String selectCmd = String.Format( "select * from Nagrania where albumId = {0} order by id", (string)recordingSelect.SelectedItem.Value); OleDbConnection myConnection = new OleDbConnection( "Provider=Microsoft.Jet.OLEDB.4.0; Data Source='c:\\Projekty\\svn\\pgui\\LN_2007\\NET\\baza.mdb'"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "nagrania"); MyDataGrid.DataSource = ds; MyDataGrid.DataBind(); }

protected void recordingSelect_SelectedIndexChanged(object sender, EventArgs e) { }</script></head>

Dalszy ciąg tego samego plikuna następnym slajdzie.

Kod uruchamiany podczas ładowania strony.

Wypełnia danymi listę rozwijalną z płytami.

Kod uruchamiany po wciśnięciu przycisku 'Pokaż'.

(czyli jest pewien typ kontrolera)

Cały kodjest wewnątrz

strony ASP.NET

Model + Kontroler?

Page 11: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

11

Na początek wszystko na stronie 2/2

<body> <form id="form1" runat="server" method="post"> <div> Album płytowy (Atchitektura Jednolita (brak MVC))</div> <br /> Wybierz płytę:<br /> <asp:DropDownList ID="recordingSelect" runat="server" Width="332px" OnSelectedIndexChanged="recordingSelect_SelectedIndexChanged" AutoPostBack="True"> </asp:DropDownList> <asp:Button ID="Button1" runat="server" Text="Pokaż" Width="99px" OnClick="SubmitBtn_Click" /> <br /> <br /> <asp:GridView ID="MyDataGrid" runat="server" Width="433px"> </asp:GridView> &nbsp;<br /> </form></body></html>

Kod ASP, który wyświetlakontrolki na formularzu.

Kod ten nie podłącza odpowiednich atrybutów kontrolek do źródeł danych.

Zajmuje się tym kod 'kontrolera' odwołując się za pomocą ID

Prezentacja?

Page 12: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

12

Demo w Microsoft Visual StudioSingle Page

Page 13: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

13

Wszystko na stronie - PodsumowanieZalety

– Bardzo prosta, – Łatwa w implementacji, – Łatwo i szybko można wykonać jakiekolwiek zmiany,– Kod jest zgromadzony w jednym pliku, przez co mamy nad nim pełną

kontrolę.– „Łatwe kopiuj+wklej”– „Mało pracy!” < pozornie, ale dobre do prototypowania

Wady– Problem z rozdzieleniem zadań między programistów i projektantów HTML,– Problemy z powstawaniem błędów,– Problem z ponownym użyciem kodu, który zapewnia dostęp do bazy

danych. (Na każdej stronie musimy umieszczać kod inicjalizujący połączenie.)

Page 14: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

14

Refaktoring 1 – (Model+Kontroler) WidokCode Behind – w .NET każda strona ASP.NET posiada dodatkowy

plik z kodem zarządzającym daną stroną ASP. W ten sposób łatwo możemy oddzielić widok od kontrolera-modelu (uwaga, ale nie kontrolera aplikacji).

Page 15: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

15

class ModelWidok.NET

Default.aspx

+ Button1: asp:Butt on+ M yDataGrid : asp:GridView+ record ingSelect: asp:DropDownList

Sy s t em.Web.UI.P age_Default

+ Page_Load(object, System .EventArgs) : void+ Subm itBtn_Cl ick(Object, EventArgs) : vo id

W pl iku: Defaul t.aspx.cs

W pl iku: Defaul t.aspx

«partia l»

Diagram klas – (Model+Kontroler) Widok

Uwaga! Ta notacja niedotyczy słowa kluczowegopartial, dla któregopowinniśmy raczej podawaćatrybuty w jednej klasie,lub ewentualnie lepiej za pomocą asocjacji.

Page 16: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

16

Refaktoring 1 - WidokCo pozostanie w naszym widoku?

Plik Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" ><head runat="server"> <title>Untitled Page</title></head><body> <form id="form1" runat="server"> <div> Album płytowy (Widok-Kontroler)</div> <br /> Wybierz płytę:<br /> <asp:DropDownList ID="recordingSelect" runat="server" AutoPostBack="True" Width="332px"> </asp:DropDownList> <asp:Button ID="Button1" runat="server" OnClick="SubmitBtn_Click" Text="Pokaż" Width="99px" /> <br /> <br /> <asp:GridView ID="MyDataGrid" runat="server" Width="433px"> </asp:GridView> </form></body></html>

class ModelWidok.NETa

Default.aspx

+ Button1: asp:Butt on+ M yDataGrid : asp:GridView+ recordingSelect: asp:DropDownList

Sy s t em.Web.UI.P age_Default

+ Page_Load(object, System .EventArgs) : vo id+ Subm i tBtn_Cl ick(Object, EventArgs) : void

«partia l»

Page 17: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

17

Refaktoring 1 - Kontroler+ModelZawartość pliku:

Default.aspx.cs

(czyli Code Behind)

using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System.Data.OleDb;

public partial class _Default : System.Web.UI.Page { public void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack) { String selectCmd = "select * from Plyty"; OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source='c:\\Temp\\baza.mdb'"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "plyty"); recordingSelect.DataSource = ds; recordingSelect.DataTextField = "tytul"; recordingSelect.DataValueField = "id"; recordingSelect.DataBind(); }

} public void SubmitBtn_Click(Object sender, EventArgs e) { String selectCmd = String.Format( "select * from Nagrania where albumId = {0} order by id", (string)recordingSelect.SelectedItem.Value); OleDbConnection myConnection = new OleDbConnection( "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\\Temp\\baza.mdb"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "nagrania"); MyDataGrid.DataSource = ds; MyDataGrid.DataBind(); }}

Kontroler, który jest jeszczenadal zintegrowany z modelem,czyli klasami odwołującymi się

do bazy danych.

Page 18: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

18

Demo w Visual Studio:Proces refaktoringu projektu Single Page.

Page 19: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

19

Refaktoring 2 - Zadanie 1Stworzyć pełny Model-Widok-Kontroler na podstawie poprzedniego

wzoru.

Przenieść fragment związany z pobieraniem danych z bazy do osobnej klasy.

class MVC.NET

Widok

Kontroler

ModelWidok.NET::Default.aspx

+ Button1: asp:Button+ M yDataGrid: asp:GridView+ recordingSelect: asp:DropDownList

System.Web.UI.PageModelWidok.NET::_Default

+ Page_Load(object, System .EventArgs) : void+ Subm itBtn_Cl ick(Object, EventArgs) : void

Model

BramaDoBazy

+ Bram aDoBazy()+ dajNagrania(string) : DataSet+ dajPlyty() : DataSet

Page 20: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

20

Co mógłby zawierać kontroler?using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page { public void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack) { recordingSelect.DataSource = BramaDoBazy.dajPlyty(); recordingSelect.DataTextField = "tytul"; recordingSelect.DataValueField = "id"; recordingSelect.DataBind(); }

} public void SubmitBtn_Click(Object sender, EventArgs e) { MyDataGrid.DataSource = BramaDoBazy.dajNagrania((string)recordingSelect.SelectedItem.Value); MyDataGrid.DataBind(); }}

Tu odwołujemy się do modeluz prośbą o udostępnienieinformacji o stanie zbioru

z płytami.

Tu odwołujemy się do modeluz prośbą o udostępnienie

stanu dotyczącego konkretnej płyty:

(string)recordingSelect.SelectedItem.Value

Page 21: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

21

Dla leniwych... (rozwiązanie)using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System.Data.OleDb;

public class BramaDoBazy{ public BramaDoBazy() {}

public static DataSet dajPlyty() { String selectCmd = "select * from Plyty"; OleDbConnection myConnection = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source='c:\\Temp\\baza.mdb'"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "plyty"); return ds; }

public static DataSet dajNagrania(string albumId) { String selectCmd = String.Format( "select * from Nagrania where albumId = {0} order by id", albumId); OleDbConnection myConnection = new OleDbConnection( "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\\Temp\\baza.mdb"); OleDbDataAdapter myCommand = new OleDbDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "nagrania"); return ds; }}

Tworzymy nową klasę iumieszczamy ją w

folderze: App_Code

Tworzymy obiekt DataSet, który będzie przechować

STAN SESJI.

Synchronizujemy stan sesji ze STANEM MODELU. W naszym przypadku stan

modelu jst w bazie danych.

Page 22: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

22

Page Controller - wprowadzenieOdseparowaliśmy model od widoku, czyli interfejs użytkownika od

logiki biznesowej.1. Teraz pora na dodanie dynamicznej nawigacji pomiędzy stronami.

● Często wciśnięcie tego samego przycisku może poprowadzić użytkownika do różnych stron w następnym kroku.

– Kasowanie e-maila w kliencie pocztowym nie zaprowadzi użytkownika do strony startowej, lecz najczęściej wyświetli następną wiadomość.

– Walidacja danych wprowadzonych w formularzu może w wyniku wyświetlić komunikat o błędzie lub przejść do następnego kroku procesu.

– Itp.

2. Jak zapewnić aby wszystkie strony zawierały wspólny nagłówek● Rozwiązanie: można zastosować wzorzec Page Controller z uwzględnieniem

dziedziczenia.

Page 23: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

23

Page Controller

class Page Controller

Model

+ Logika Biznesowa:

Page Controller

- Obsluz zadanie HT T P (request): - Uaktualni j m odel i zdecyduj o nastepnym widoku:

Widok

- Wygeneruj HT M L:

Page 24: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

24

Eliminacja duplikacji koduW celu wyeliminowania powtarzających się fragmentów kodu

(np. walidacji parametrów) można zastosować kontroler bazowy.

class Kontroler Bazowy

KontrolerBazowy

- Wspolna funkcjonalnosc (m etody):

KontrolerStrony_1

- Funkcje specyficzne dla strony 1:

KontrolerStrony_2

- Funkcje specyficzne dla strony 2:

Page 25: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

25

A automatyczne testy?

class KontrolerBazowyTesty

KontrolerBazowy

- Wspolna funkcjonalnosc (m etody):

KontrolerStrony_1

- Funkcje specyficzne d la strony 1:

KontrolerStrony_2

- Funkcje specyficzne d la strony 2:

System.Web.UI.PageModelWidok.NET::_Default

+ Page_Load(object, System .EventArgs) : void+ Subm itBtn_Cl ick(Object, EventArgs) : void

ModelWidok.NET::Default.aspx

+ Button1: asp:Button+ M yDataGrid: asp:GridView+ recordingSelect: asp:DropDownList

«partia l»

– Problem: Aby wykonać testy naszej aplikacji musielibyśmy uruchamiać serwer aplikacji...

(verte)

Page 26: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

26

A automatyczne testy?

class KontrolerBazowyTesty

KontrolerBazowy

- Wspolna funkcjonalnosc (m etody):

KontrolerStrony_1

- Funkcje specyficzne dla strony 1:

KontrolerStrony_2

- Funkcje specyficzne dla strony 2:

System.Web.UI.PageModelWidok.NET::_Default

+ Page_Load(object, System .EventArgs) : void+ Subm i tBtn_Cl ick(Object, EventArgs) : void

ModelWidok.NET::Default.aspx

+ Button1: asp:Button+ M yDataGrid: asp:GridView+ recordingSelect: asp:DropDownList

«partia l»

– Problem: Aby przetestować musielibyśmy uruchamiać serwer aplikacji...

1. Tutaj będzie znajdować się cały kod zależny

od ASP.NET

2. Będziemy przekazywaćparametry w formie niezlaeżnej

od HTTP. (np. w postaci kolekcji)

3. Kontroler możemy wykorzystaćrównież w innych aplikacjach!

(Nawet typu Desktop.)

Page 27: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

27

A automatyczne testy?

class KontrolerBazowyTesty

KontrolerBazowy

- Wspolna funkcjonalnosc (m etody):

KontrolerStrony_1

- Funkcje specyficzne dla strony 1:

KontrolerStrony_2

- Funkcje specyficzne dla strony 2:

System.Web.UI.PageModelWidok.NET::_Default

+ Page_Load(object, System .EventArgs) : void+ Subm i tBtn_Cl ick(Object, EventArgs) : void

ModelWidok.NET::Default.aspx

+ Button1: asp:Button+ M yDataGrid: asp:GridView+ recordingSelect: asp:DropDownList

«partia l»

Teraz aby utworzyć testyautomatyczne kontrolera

nie musimysymulować żądań HTTP

(Request)

Zależy od zapytania HTTP

Nie zależy od zapytania HTTP

Page 28: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

28

A automatyczne testy?

class KontrolerBazowyTesty

KontrolerBazowy

- Wspolna funkcjonalnosc (m etody):

KontrolerStrony_1

- Funkcje specyficzne dla strony 1:

KontrolerStrony_2

- Funkcje specyficzne dla strony 2:

System.Web.UI.PageModelWidok.NET::_Default

+ Page_Load(object, System .EventArgs) : void+ Subm i tBtn_Cl ick(Object, EventArgs) : void

ModelWidok.NET::Default.aspx

+ Button1: asp:Button+ M yDataGrid: asp:GridView+ recordingSelect: asp:DropDownList

«partia l»

CodeBehind pełni rolępośredniego model prezentacji,

wykonujący transformacjęelementów z postaci HTTP

na postać z dziedziny aplikacji lub do postaci ogólnych kolekcji.

Kontroler uniwersalny,niezależny od samego

zapytania HTTP.

Page 29: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

29

Page Controller - Podsumowanie– Zalety

– Prostota – ponieważ każda strona jest zarządzana przez własny kontroler. Wzorzec jest zalecany dla stron ze stosunkowo prostą nawigacją.

– Jest wzorcem wbudowanym i zalecanym przez .NET– Zastosowanie kontrolera bazowego zwiększa ponowne użycie kodu.– Rozszerzalność – bardziej złożona logika może być delegowana do oddzielnych

klas pomocniczych.– Rozdzielenie zadań programisty od projektanta www.

– Ograniczenia– Jeden kontroler dla każdej strony – sprawdza się gdy mamy w miarę statyczną

strukturę stron aplikacji oraz nawigacji między nimi.– Głębokie zależności dziedziczenia – prowadzą do trudnych do utrzymania i rozwoju

projektów. Dodatkowo często wymagają wielu operacji warunkowych. W przypadku bardzo skomplikowanego systemu rozważ zastosowanie wzorca Front Controller.

– W klasycznej postaci nie umożliwia wykonywania automatycznych testów. Kontroler zależy od zawartości formularza na stronie, czyli od specyficznych pól zawartych w obiekcie Request. Dopiero zastosowanie dodatkowego kontrolera dedykowanego do samego ASP.NET.

Page 30: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

30

Założenia do Front ControllerProblem: Jaka jest najkorzystniejsza architektura dla skomplikowanej

aplikacji Web aby osiągnąć wysoki wskaźnik ponownego użycia kodu oraz elastyczności przy jak najmniejszym duplikowaniu kodu.

Problem: Wspólna funkcjonalność jest dzielona przez wiele widoków.– Potrzebna jest centralizacja tej logiki aby uniknąć powtarzania się kodu.

Problem: Zbiór widoków wykorzystuje te same dane.– Najkorzystniejszym rozwiązaniem jest scentralizowane pobieranie danych.

Czyli unikamy powtarzania się kodu odpowiedzialnego za pobieranie danych w poszczególnych widokach.

Problem: Automatyczne testowanie.– Testować chcemy nie tylko model, ale także kontroler.

Page 31: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

31

Front Controller - WprowadzenieW Page Controller:

– mamy jednego potomka wszystkich stron, ale którego funkcjonalność z czasem rozrasta się do bardzo dużych rozmiarów,

– aby uniknąć warunków w klasie bazowej musimy budować skomplikowane i złożone struktury dziedziczenia,

– zarządza JEDNĄ stroną, czyli trudno jest nam zrealizować zarządzanie nawigacją, czyli logikę aplikacji,

– zarządza jedną stroną a więc trudno jest w jednym miejscu zrealizować WSPÓLNĄ część funkcjonalności aplikacji (komunikaty, bezpieczeństwo, itp.)

– przywiązanie strony, formularza do konkretnego URLa, również wprowadza ograniczenie do aplikacji (wyobraźmy sobie np. kreator, gdzie potrzebne byłyby operacje warunkowe w kontrolerze bazowym)

Page 32: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

32

Front Controller - WprowadzenieRozwiązanie: Filtracja wszystkich zapytań przez JEDEN główny

kontroler.

Front Kontroler jest realizowany w dwóch częściach: Handler (obsługa) oraz hierarchii akcji (Concrete Command)– Zadania Handlera:

● Pobranie parametrów bezpośrednio z zapytania HTTP.● Selekcja akcji (komendy, command) do ruchomienia.

– Komendy są częścią kontrolera.● Po zakończeniu operacji przez komendę wybiera ona widok do wyświetlenia.

Zaleta:– scentralizowane zarządzanie – bezpieczeństwo wątkowe– możliwość konfiguracji

Page 33: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

33

Struktura i scenariusz Front Controllera

Struktura

Scenariusz

Page 34: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

34

ImplementacjaW .Net implementacja jest skomplikowana ze względu na

wbudowany i ściśle zintegrowany ze środowiskiem wzorzec Page Controllera.– Potrzebna jest budowa całego silnika Front Controllera.– Należy stosować tylko i wyłącznie dla faktycznie rozbudowanych systemów.

Zakładamy, że potrzebujemy stworzyć dwie strony z wspólnym nagłówkiem.

Page 35: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

35

Kod klasy bazowejusing System;using System.Web.UI;using System.Web.UI.WebControls;public class BasePage : Page{ protected Label eMail; protected Label siteName; virtual protected void PageLoadEvent(object sender, System.EventArgs e) { } protected void Page_Load(object sender, System.EventArgs e) { if (!IsPostBack) { string name = Context.User.Identity.Name; eMail.Text = DatabaseGateway.RetrieveAddress(name); siteName.Text = "Micro-site"; PageLoadEvent(sender, e); } } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer. // InitializeComponent(); base.OnInit(e); } /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.Load += new System.EventHandler(this.Page_Load); } #endregion}

Page 36: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

36

Projekt obiektu Handlerusing System;using System.Web;public class Handler : IHttpHandler{ public void ProcessRequest(HttpContext context) { Command command = CommandFactory.Make(context.Request.Params); command.Execute(context); } public bool IsReusable { get { return true; } }}

using System;using System.Web;public interface Command{ void Execute(HttpContext context);}

using System;using System.Collections.Specialized;

public class CommandFactory{ public static Command Make(NameValueCollection parms) { string siteName = parms["site"]; Command command = new UnknownCommand(); if (siteName == null || siteName.Equals("micro")) command = new MicroSite(); else if (siteName.Equals("macro")) command = new MacroSite(); return command; }}

Page 37: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

37

Konfiguracja „Handlera”

<httpHandlers><add verb="*" path="Page*.aspx" type="Handler,FrontController" /></httpHandlers>

Plik konfiguracyjny:

Page 38: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

38

Komendy

Page 39: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

39

RedirectingCommand

using System;using System.Web;public abstract class RedirectingCommand : Command{ private UrlMap map = UrlMap.SoleInstance; protected abstract void OnExecute(HttpContext context); public void Execute(HttpContext context) { OnExecute(context); string url = String.Format("{0}?{1}", map.Map[context.Request.Url.AbsolutePath], context.Request.Url.Query); context.Server.Transfer(url); }}

Page 40: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

40

UrlMap

public class UrlMap : IConfigurationSectionHandler{ private readonly NameValueCollection _commands = new NameValueCollection(); public const string SECTION_NAME = "controller.mapping"; public static UrlMap SoleInstance { get { return (UrlMap)ConfigurationSettings.GetConfig(SECTION_NAME); } } object IConfigurationSectionHandler.Create(object parent, object configContext, XmlNode section) { return (object)new UrlMap(parent, configContext, section); } private UrlMap() {/*no-op*/} public UrlMap(object parent, object configContext, XmlNode section) { try { XmlElement entriesElement = section["entries"]; foreach (XmlElement element in entriesElement) { _commands.Add(element.Attributes["key"].Value, element.Attributes["url"].Value); } } catch (Exception ex) { throw new ConfigurationException("Error while parsing configuration section.", ex, section); } } public NameValueCollection Map { get { return _commands; } }}

<controller.mapping><entries><entry key="/patterns/frontc/3/Page1.aspx" url="ActualPage1.aspx" /><entry key="/patterns/frontc/3/Page2.aspx" url="ActualPage2.aspx" /></entries></controller.mapping>

Page 41: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

41

MicroSite

using System;using System.Web;public class MicroSite : RedirectingCommand{ protected override void OnExecute(HttpContext context) { string name = context.User.Identity.Name; context.Items["address"] = WebUsersDatabase.RetrieveAddress(name); context.Items["site"] = "Micro-Site"; }}

Page 42: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

42

MacroSite

using System;using System.Web;public class MacroSite : RedirectingCommand{protected override void OnExecute(HttpContext context) { string name = context.User.Identity.Name; context.Items["address"] = MacroUsersDatabase.RetrieveAddress(name); context.Items["site"] = "Macro-Site"; }}

Page 43: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

43

Warstwa Modelu...Dostęp do danych...

using System;using System.Data;using System.Data.SqlClient;public class WebUsersDatabase{ public static string RetrieveAddress(string name) { string address = null; String selectCmd = String.Format("select * from webuser where (id = '{0}')", name); SqlConnection myConnection = new SqlConnection("server=(local);database=webusers;Trusted_Connection=yes"); SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "webuser"); if (ds.Tables["webuser"].Rows.Count == 1) { DataRow row = ds.Tables["webuser"].Rows[0]; address = row["address"].ToString(); } return address; }}

using System;using System.Data;using System.Data.SqlClient;

public class MacroUsersDatabase{ public static string RetrieveAddress(string name) { string address = null; String selectCmd = String.Format("select * from customer where (id = '{0}')", name); SqlConnection myConnection = new SqlConnection("server=(local);database=macrousers;Trusted_Connection=yes"); SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection); DataSet ds = new DataSet(); myCommand.Fill(ds, "customer"); if (ds.Tables["customer"].Rows.Count == 1) { DataRow row = ds.Tables["customer"].Rows[0]; address = row["email"].ToString(); } return address; }}

Dla Micro-Site:

Dla Macro-Site:

Page 44: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

44

Front Controller – Wady i ZaletyZalety:

– Większa elastyczność (np. poprzez plik konfiguracyjny)– Uproszczone widoki (bez obsługi akcji)– Gotowe na rozbudowę i modyfikacje– Mapowanie URL (ukrycie nazw stron przed użytkownikiem)– Bezpieczeństwo wątkowe

Wady:– Obniżona wydajność– Zwiększone skomplikowanie kodu, pogorszona czytelność i odkrywalność– Front Controller jest zaimplementowany w ASP.NET – trudne testowanie w

oddzieleniu od serwera aplikacji– Brak weryfikacji nieprawidłowych URL (ponieważ znajduje się to tylko w

pliku konfiguracyjnym)

Page 45: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

45

Page CacheAby przyspieszyć wyświetlanie stron, które wymagają długiego czasu

do generacji możemy je na jakiś czas przechowywać w pamięci podręcznej.

Brak w cache Znajdujący się w cache

Page 46: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

46

Page Cache - implementacja

<%@ OutputCache Duration="60" VaryByParam="none" %><html><script language="C#" runat="server">void Page_Load(Object sender, EventArgs e){TimeMsg.Text = DateTime.Now.ToString("G");}</script><body><h3>Using the Output Cache</h3><p>Last generated on: <asp:label id="TimeMsg" runat="server"/></body></html>

W .NET wzorzec Page Cache jest wbudowany w serwer aplikacji.

Page 47: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

47

Wzorzec Łańcuch Filtrów (Filter Chain)

Struktura

Typowy scenariusz

Page 48: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

48

Przykładowe zastosowanieFiltry przechwytują zdarzenia Przed... i Po.. (Before... i After...)

– Analiza nagłówków– Analiza pól– Uruchomienie logiki– Zwrócenie nagłówków– Zwrócenie treści

Page 49: Projektowanie Graficznych Interfejsów Użytkownikaprpw.iem.pw.edu.pl/wyniki.21-3/pgui/L8_wzorce_web.pdfPage Controller - wprowadzenie Odseparowaliśmy model od widoku, czyli interfejs

49

Interakcja

Dziękuję za uwagę.

Chcemy być coraz lepsi!

Jeżeli coś cię zainteresowało napisz e-maila:– [email protected]

Jeżeli coś cię bardzo znudziło napisz e-maila:– [email protected]

Jeżeli zauważyłeś błąd napisz e-maila:– [email protected]