Wzorce prezentacji internetowych

1. Model kontrolera widoku (Model View Controller). 2. Kontroler strony (Page Controller). 3. Kontroler fasady (Front Controller). 4. Szablon widoku (Template View). 5. Widok przekształcający (Transform View). 6. Widok dwuetapowy (Two Step View) 7. Kontroler aplikacji (Application Controller).

1

Model View Controller

Kontroler

Widok

Model

Obsługa interfejsu użytkownika jest rozdzielona między trzy odrębne elementy (role). 2

Model View Controller Model – obiekt reprezentujący dziedzinę. Posiada wszystkie dane i udostępnia operacje nie związane z obsługą interfejsu użytkownika. Widok – prezentacja modelu (danych) poprzez interfejs użytkownika. Kontroler – odpowiada za interakcje z użytkownikiem – pobiera dane i na ich podstawie modyfikuje model. Kluczową kwestią w tym wzorcu projektowym jest rozdzielenie danych od ich prezentacji. Rozdział pomiędzy widokiem a kontrolerem jest wyraźny jedynie w przypadku interfejsu WWW. 3

Page Controller

Kontroler strony

Widok

Model

Kontroler strony obsługuje żądania kierowane do konkretnej strony lub funkcji udostępnianej przez serwis internetowy. 4

Page Controller W ramach tego wzorca tworzony jest osobny kontroler dla każdej strony internetowej. Kontroler strony może być zaimplementowany zarówno w formie skryptu (np. cgi, serwlet) jak i strony (JSP, PHP, ASP, itp.). Podstawowe obowiązki kontrolera strony to: ●

dekodowanie adresu URL i pobieranie przesłanych informacji (GET,

POST, Cookies, Sessions), ●

utworzenie i wywołanie wszelkich obiektów modelu niezbędnych do

przetworzenia danych, ●

Wybór widoku i przekazanie mu wszelkich, uprzednio

przygotowanych operacji.

5

Page Controller class BasketController...{ public init(HttpServletRequest request){ Basket b = null; try{ bid = Integer.parseInt(request.getParameter("bid")); b = BasketHelper.findOrCreate(bid); }catch(NullPointerException ex){ b = BasketHelper.createNew(); } request.setAttribute("basket", b); }

}

public doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException this.init(request); RequestDispatcher dispatcher = this.getServletContext(). getRequestDispatcher("basket.jsp"); dispatcher.forward(request, response); }

6

Page Controller

Kontrolerem może być tez strona JSP, która następnie wyświetli przygotowany wynik. W takim przypadku zwykle przygotowanie danych powierza się klasom pomocniczym, aby nadmiernie nie komplikować scriptlet'ów umieszczonych w kodzie strony.

Bardziej eleganckim rozwiązaniem jest implementacja własnego tagu.

7

Page Controller public class HelperTag extends TagSupport{ public static final String HELPER = "helper"; protected Object getProperty(String s) throws JspException{ Object helper = this.getHelper(); try{ Method m = helper.getClass(). getMethod(this.getter(s), null); return m.invoke(helper, null); }catch(Exception ex){ throw new JspException("..."); } } private String getter(String s) { return "get"+s.substring(0, 1).toUpperCase()+ s.substring(1); }

}

private Object getHelper() throws JspException { Object helper = this.pageContext.getAttribute(HELPER); if (helper==null) throw new JspException("..."); return helper; } 8

Page Controller class HelperInitTag extends HelperTag{ private String sClass; public void setName(String s){ this.sClass = s; } @Override public int doStartTag() throws JspException { HelperController helper = null;

}

try { helper = (HelperController) Class.forName(this.sClass).newInstance(); } catch (Exception ex) { throw new ApplicationException("..."); } this.initHelper(helper); this.pageContext.setAttribute(HELPER, helper); return SKIP_BODY; 9

Page Controller private void initHelper(HelperController helper){

}

}

HttpServletRequest request = (HttpServletRequest) this.pageContext.getRequest(); HttpServletResponse response = (HttpServletResponse) this.pageContext.getResponse(); helper.init(request, response);

Wszystkie własne tagi muszą być zadeklarowane w odpowiednim deskryptorze tld (Tag Library Descriptor). W kodzie strony musi znaleźć się też odpowiednia dyrektywa, np.

10

Page Controller class HelperGetTag extends HelperTag{ private String sProperty; public void setProperty(String s){ this.sProperty = s; }

}

public int doStartTag() throws JspException{ try { this.pageContext.getOut(). print(this.getProperty(sProperty)); } catch (IOException e) { throw new JspException("..."); } return SKIP_BODY; }

Przy okazji definiujemy tag wyświetlający własności. 11

Front Controller Kontroler fasady

Akcja abstrakcyjna

doGet() doPost()

Akcja 1

Akcja 2

Akcja 3

Kontroler fasady obsługuje wszystkie żądania kierowane do serwisu. Po analizie parametrów wejściowych wywoływane są odpowiednie polecenia. 12

Front Controller

Zalety w stosunku do Page Controller: ●

prostsza konfiguracja serwera WWW. Dodawanie nowych akcji nie

wymaga zmian w konfiguracji, ●

obiekty akcji są tworzone niezależnie dla każdego żądania – brak

problemów z wielowątkowością, chyba że inne obiekty (np. obiekty dziedziny) są współdzielone, ●

naturalna realizacja kodu wspólnego, który byłby realizowany przez

wszystkie kontrolery stron (np. obsługa błędów, autoryzacji, itp.), ●

łatwa rozbudowa dzięki dekoratorom (wzorzec Intercepting Filter).

13

Front Controller W poniższym przykładzie kontroler fasady tworzy obiekt command na podstawie danych zawartych w żądaniu a następnie przekierowuje do niego sterowanie. public class FrontServlet extends HttpServlet{ public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ FrontCommand command = this.getCommand(request); command.init(this.getServletContext(), request, response); command.process(); }

14

Front Controller

}

private FrontCommand getCommand(HttpServletRequest request) throws ApplicationException{ Class c; String sClass = "frontController." + request.getParameter("command") + "Command"; try { c = Class.forName(sClass); } catch (ClassNotFoundException e) { c = UnknownCommand.class; } try { return (FrontCommand)c.newInstance(); } catch (Exception ex) { throw new ApplicationException("..."); } }

15

Front Controller public abstract class FrontCommand { protected ServletContext context; protected HttpServletRequest request; protected HttpServletResponse response; public void init(ServletContext ctx, HttpServletRequest req, HttpServletResponse res){ this.context = ctx; this.request = req; this.response = res; } abstract public void process() throws ServletException, IOException;

}

protected void forward(String s) throws ServletException, IOException { RequestDispatcher dispatcher = this.context. getRequestDispatcher(s); dispatcher.forward(this.request, this.response); } 16

Front Controller class BasketCommand extends FrontCommand{ @Override public void process() throws ServletException, IOException { Basket b = null; try{ int bid = Integer.parseInt( request.getParameter("bid")); b = BasketHelper.findOrCreate(bid); }catch(Exception ex){ b = BasketHelper.createNew(); } request.setAttribute("basket", b); this.forward("/basket.jsp"); } } class UnknownCommand extends FrontCommand{ @Override public void process() throws ServletException, IOException { this.forward("/unknown.jsp"); } } 17

Template View Dynamiczna strona HTML jest projektowana tak jakby była stroną statyczną. Dodatkowe informacje, generowane na podstawie żądania klienta są umieszczone w kodzie HTML dzięki specjalnym znacznikom. Tak przygotowany szablon jest przetwarzany w trakcie przygotowania odpowiedzi przez serwer. Znaczniki zostają wtedy zastąpione wynikami obliczeń, informacjami pobranymi z bazy danych, itp. Wzorzec ten jest stosowany przez wiele różnych narzędzi (PHP, JSP, ASP, ...), dlatego w praktyce nie istnieje potrzeba jego implementacji a jedynie umiejętnego wykorzystania. Podstawowa zaleta szablonów to brak wymagań dotyczących znajomości języka programowania przez osoby projektujące interfejs HTML. 18

Template View Wskazówki dotyczące korzystania ze wzorca Template View: ●

nie stosujemy scriptletów – prowadzi to do wymieszania logiki

aplikacji z widokiem. W razie potrzeby należy stosować obiekty pomocnicze, ●

unikamy wyrażeń warunkowych:



w miarę możliwości zastępujemy przez:

19

Transform View Model przekształcenie

HTML

Widok jest tworzony poprzez przekształcenie obiektu dziedziny w dokument HTML. Najczęściej model reprezentuje się w formie XML'a przekształcanego za pomocą XSLT. 20

Transform View

Wybór pomiędzy Template View a Transform View jest uwarunkowany preferencjami programistów oraz dostępnością narzędzi. Podstawowe zalety Transform View: ●

niezależność od platformy (technologii) internetowej,



naturalna współpraca z danymi w formacie XML,



brak logiki aplikacji w widoku,



łatwiejsze testowanie niż Template View (nie potrzeba serwera www).

Problemy: ●

trudno zmienić ogólny wygląd strony.

21

Two Step View Model

przekształcenie 1 HTML

Ekran logiczny

przekształcenie 2

Widok dwuetapowy tworzy kod HTML w dwóch krokach. W pierwszym, na podstawie obiektów dziedziny tworzony jest „logiczny obraz” strony, który następnie jest przetwarzany do dokumentu HTML. 22

Two Step View Widok dwuetapowy ułatwia globalną zmianę wszystkich stron w serwisie internetowym. Najczęstsze implementacje: ●

podwójne przekształcenie XSLT. Pierwsze tworzy dokument XML

opisujący stronę, drugie generuje kod HTML. ●

opis logicznej strony przez zbiór klas, która następnie jest

przekształcana do HTML'a (w calości bądź poprzez przekształcenia każdej z klas składowych), ●

logiczny ekran opisany poprzez wzorzec Template View nie

zawierający znaczników HTML (zwykle prowadzi to do dokumentu w formacie XML). Przekształcenia szablonu prowadzą do strony HTML.

23

Application Controller

Kontroler aplikacji ma na celu zcentralizowanie zarządzania dostępnymi kontrolerami i widokami. Wzorzec ten jest wykorzystywany, gdy chcemy implementować logikę aplikacji polegającą na prezentacji sekwencji stron www prowadzącej do zrealizowania określonego celu. (np. złożenie zamówienia, ankieta, test, wypełnianie zaawansowanych formularzy, itp.)

24

Application Controller

class FrontServlet...

}

public void service(HttpServletRequest request, HttpServletResponse response){ ApplicationController controller = this.getApplicationController(request); String sCommand = request.getParameter("command"); DomainCommand com = controller.getDomainCommand(sCommand, request.getParameterMap()); com.run(request.getParameterMap()); String sView = "/" + controller.getView(sCommand, request.getParameterMap()) + ".jsp"; this.forward(sView, request, response); }

25

Podsumowanie

Zaprezentowane wzorce przedstawiają najczęstsze metody projektowania warstwy prezentacji internetowych. Jedną z istotnych cech przedstawionych wzorców jest to, że można je stosować równolegle. Umożliwia to elastyczne dostosowanie rozwiązań informatycznych do potrzeb poszczególnych modułów aplikacji internetowych.

26