Tuesday, June 24, 2008

Wzorce projektowe warsty prezentacji



Dokument w wersji PDF można pobrać z tego miejsca http://www.deltasoftware.pl/dokumenty/Michal_Stanek-Wzorce_Projektowe.pdf

Wstęp


Wzorce projektowe są ogólnymi rozwiązaniami popularnych problemów, jakie pojawiają się podczas projektowania systemów informatycznych. Użycie przetestowanych i efektywnych rozwiązań pozwala zminimalizować koszty oraz skrócić czas potrzebny do wytworzenia oprogramowania. Polepszeniu ulega także komunikacja między ekspertami i zespołami projektowymi.

Dokument ten omawia wzorce projektowe warstwy prezentacji, na przykładzie platformy J2EE. Po wstępnym omówieniu problemów związanych z tworzeniem nowoczesnych aplikacji biznesu elektronicznego, przedstawione zostały trzy wzorce projektowe warstwy prezentacji: Intercepting Filter, Context Object, Composite View. Każdy wzorzec został ogólnie omówiony, przedstawiono diagramy klas oraz sekwencji, przedstawiono również przykładowe strategie implementacji.

Projektowanie aplikacji J2EE



Specyfikacja J2EE powstała z myślą o zaspokojeniu potrzeb developerów aplikacji biznesu elektronicznego. Zawiera ona takie składowe jak strony JSP, komponenty JSP, usługi nazw jak JNDI, i wiele innych. Każdy z tych składników w mniejszym lub większym stopniu zaspokaja potrzeby


  1. EJB - Reprezentuje komponent Enterprise Java Bean, związany jest z reguły z obiektem biznesowym. Rolę tę pełni zazwyczaj komponent sesyjny lub Entity.


  2. JSP - Java Server Pages. Technologia związana z generowanie widoku za pomocą osadzenia kody Javy na stronie HTML. Kod Javy zawarty jest w specjalnych znacznikach, a sama strona JSP wykonywana jest przez serwer servletów.



Trzeba zdawać sobie sprawę z tego, że wiele, a można byłoby zaryzykować twierdzenie, że większość dzisiejszych aplikacji biznesu elektronicznego wykorzystuje możliwości, jakie dają sieci komputerowe. Projektanci stają wobec tego przed zupełnie nowymi wyzwaniami, wśród których wyróżnić można aspekt związany z rozproszeniem, dostępnością, bezpieczeństwem itp. Tym własnie wyzwanią stawiają czoła wzorce projektowe opracowane dla platformy J2EE przez konsorcjum Sun Java Center. Niniejszy dokument skupi sie na omówieniu trzech wzorców warstwy prezentacji.


Wzorce projektowe w J2EE



Wzorce projektowe są ogólnymi rozwiązaniami popularnych problemów, jakie pojawiają się podczas projektowania systemów informatycznych. Użycie przetestowanych i efektywnych rozwiązań pozwala w efekcie uzyskać lepsze rozwiązania charakteryzujące się miedzy innymi:


  1. Poprawionym aspektem przyszłej pielęgnacji aplikacji.

  2. Lepszą modułowością.

  3. Możliwością rozdzielenia ról członków zespołu projektowo-programistycznego.

  4. Wielokrotnym wykorzystaniem komponentów.
  5. Poprawieniem bezpieczeństwa dostępu.

  6. Redukcją intensywności komunikacji sieciowej.

  7. Zminimalizowanym kosztem wytworzenia.



Podczas projektowania systemów J2EE, często napotykamy podobne problemy. Warto przyjrzeć się kilku z nim, aby zrozumieć jak wielką rolę odgrywają dzisiaj wzorce projektowe.

Często zdarza się, że niedoświadczony programista zawiera na stronie JSP kod odpowiedzialny za wygląd (HTML), logikę biznesową(Java) oraz dostęp do bazy danych(SQL). Wprowadzenie modułu sterującego pozwoliłoby uzyskać rozwiązanie zdecydowanie lepsze. Poprawiona zostałaby modułowość, jak również przyszła możliwość modyfikacji tak utworzonego kodu.



Równie istotnym zagadnieniem jest wydzielenie kodu odpowiedzialnego za logikę biznesową z elementu odpowiedzialnego za przygotowanie widoku. Ponieważ strony JSP pozwalają umieszczać w ich wnętrzu kod Javy, programiści bardzo często umieszczają w nich typowe akcje związane z logiką biznesową. Są one niezależne i niezwiązane z formą ich prezentacji i powinny zostać wydzielone do oddzielnych klas np. Enterprise JavaBeans.

Podobnym problemem związanym ze stronami JSP, jest umieszczenie w nich kodu odpowiedzialnego za przygotowanie oraz konwersję danych. Stwarza to kłopoty związane z redundancją kodu. Rozwiązaniem tego problemu, tak jak poprzednio jest wydzielenie kodu konwersji do oddzielnych klas.



Programiści aplikacji internetowych napotykają również często na dwa inne problemy. Pierwszy z nich związany jest z odpowiednim ukrywaniem zasobów przed klientem, który najpierw powinien spełnić pewne warunki, np. przejść poprawnie proces logowania do systemu.




Drugi problem związany jest ze specyfikacją protokołu http, a dokładniej ze sposobem komunikacji przeglądarki z serwerem. Często zdarza się, że żądanie wykonania pewnej akcji zostaje powielone. W przypadku kiedy taka akcja powoduje modyfikacje danych, należy wyeliminować takie żądanie. Rozwiązaniem tych problemów może być wprowadzenie modułu sterującego takiego jak front controller [ALUR2004].




Doświadczony programista zdaje sobie również sprawę z faktu, że uzależnienie aplikacji od protokołu, w jakim pracuje, znacznie ogranicza jej późniejszy rozwój. W obecnych czasach, wraz z bardzo dynamicznych rozwojem urządzeń mobilnych jest to szczególnie istotne, aby aplikacja mogła pracować w wielu różnych środowiskach, a komunikacja z nią byłą możliwa za pomocą dowolnej ilości protokołów. Wzorzec projektowy o nazwie Context Object, stanowi rozwiązanie tego problemu.




Jest to tylko kilka problemów, z jakimi możemy spotkać się projektując aplikację sieci WWW pracującą nie tylko w technologii J2EE. Warto zaznajomić się jednak ze wszystkimi wzorcami projektowymi, gdyż wielu przypadkach nie musimy wynajdywać tak zwanego "koła" od nowa, a wypracowane przez społeczność programistów rozwiązania wielokrotnie zaspokajają wszystkie nasze potrzeby. W kolejnej części tego dokumentu omówię dokładniej trzy spośród wielu istniejących wzorców.

Wzorce projektowe J2EE warstwy prezentacji



Intercepting Filter



Często możemy spotkać się z sytuacją, w której przed przystąpieniem do właściwego przetwarzania żądania strony JSP, musimy wstępnie przetworzyć dane. Operacja ta może być przykładowo związana z przetworzeniem kodowania parametrów żądania klienta. Nie trudno sobie wyobrazić, że taka konwersja musi się pojawić na każdej stronie, która w jakikolwiek sposób wykorzystuje parametry żądania klienta. Interesuje nas wobec tego rozwiązanie, którego nie będzie trzeba integrować z głównym przetwarzaniem. Wzorzec Intercepting Filter powinniśmy stosować właśnie wtedy, gdy chcemy przechwycić i modyfikować żądanie i odpowiedź przed i po właściwym przetwarzaniu. Ogólny schemat ideowy tego rozwiązania znajduje się na poniższym rysunku:



Intercepting Filter najczęściej stosowany jest do:

  1. Sprawdzenie, czy z klientem związana jest poprawna sesja.

  2. Sprawdzenie, czy obsługiwany jest dany rodzaj przeglądarki.

  3. Sprawdzenie, jakiego kodowania używa klient do wysyłania danych oraz konwersja tych danych.

  4. Deszyfrowanie lub dekompresja strumienia danych.Sprawdzenie, czy z klientem związana jest poprawna sesja.

  5. Sprawdzenie, czy obsługiwany jest dany rodzaj przeglądarki.

  6. Sprawdzenie, jakiego kodowania używa klient do wysyłania danych oraz konwersja tych danych.

  7. Deszyfrowanie lub dekompresja strumienia danych.



Typowym rozwiązaniem tego typu problemów jest umieszczenie szeregu zagnieżdżonych instrukcji if-then-else. Ponieważ jednak kod taki trzeba umieścić w każdym elemencie naszej aplikacji uzyskujemy bardzo dużą redundancję kodu. Naszym celem jest więc zastosowanie rozwiązania charakteryzującego się następującymi właściwościami.



  1. Będzie stanowić scentralizowane, wspólne przetwarzanie dla wszystkich żądań (np. sprawdzanie kodowania).

  2. Nie będzie mocno związane z kodem przetwarzania zasadniczego.

  3. Będzie umożliwiać stosowanie niezależnych komponentów, które w łątwy sposób mogą być dodawane przed lub po zasadniczym przetwarzaniu.



Na dwóch poniższych rysunkach przedstawione zostały diagramy klas oraz diagramy sekwencji wzorca Intercepting Filter.






Opis poszczególnych elementów wzorca:


  • FilterManager - jest menadżerem filtrów. Jego zadaniem jest tworzenie obiektu FilterChain oraz ustawienie odpowiedniej sekwencji wywoływanych filtrów. FilterManager może być konfigurowalny za pomocą zewnętrznego pliku konfiguracyjnego, który określa w jakiej kolejności i jakie filtry zostaną wywołane.
  • FilterChain - stanowi uporządkowany zbiór niezależnych od siebie filtrów. FilterChain odpowiedzialny jest również za koordynowanie wywołań poszczególnych filtrów.

  • Filter - reprezentuje niezależny filtr.

  • Target - stanowi zasób żądania.



Najczęstszą implementacją wzorca Intercepting Filter jest wykorzystanie strategii filtru standardowego [ALUR2004]. Strategia ta zakłada wykorzystanie standardowego mechanizmu tworzenia łańcuchów filtrów, zdefiniowanego w specyfikacji serwletów w wersji 2.3. Filtry tak utworzone bazują na standardowym interfejsie javax.servlet.Filter i są luźno powiązane ze sobą oraz docelowymi zasobami. Kontrola tak utworzonych filtrów odbywa się w sposób deklaratywny, za pomocą deskryptora wdrożenia.

Zastosowanie takiego podejścia pozawala nam uzyskać rozwiązanie uniwersalne, w którym każdy filtr stanowi niezależny komponent. W przyszłości istnieje możliwość ponownego wykorzystania tak przygotowanych filtrów, lub też użycia filtrów dostarczonych przez innych. Deklaratywny sposób zarządzania filtrami za pomocą deskryptora wdrożenia umożliwia napisanie aplikacji, która nieświadoma jest obecności filtrów. W żaden sposób nie są one, ani zarządzanie nimi związane z zasadniczym kodem przetwarzania. Jako przykład takiego rozwiązania przedstawię filtr, zajmujący się konwersją kodowania różnego rodzaju kodowań formularzy stron WWW. Przedstawiany kod będzie przykładem wykorzystania wzorca Intercepting Filter do implementacji wzorca o nazwie Łańcuch odpowiedzialności. Struktura klas przykładu przedstawiona jest na poniższym rysunku.


Interceptring Filter - strategia filtru standardowego

Klasa bazowa implementująca podstawowe metody klasy Filter, z niej będą dziedziczyć klasy StandardEncodeFilter - zajmująca się przetwarzaniem formularzy standardowych (application/x-www-form-urlencoded) oraz klasa MultipartEncodeFilter - zajmująca się przetwarzaniem formularzy umożliwiających wysyłanie plików


public class BaseEncodeFilter implements javax.servlet.Filter {

private javax.servlet.FilterConfig myFilterConfig;
public void doFilter(javax.servlet.ServletRequest servletRequest,
javax.servlet.ServletResponse servletResponse,
javax.servlet.FilterChain filterChain)
throws java.io.IOException,
javax.servlet.ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}

public javax.servlet.FilterConfig getFilterConfig() {
return myFilterConfig;
}

public void destroy() { }

public void init(javax.servlet.FilterConfig filterConfig)
throws javax.servlet.ServletException {
myFilterConfig = filterConfig;
}
}


Klasa odpowiedzialna za przetwarzanie formularzy standardowych:



public class StandardEncodeFilter extends BaseEncodeFilter {
// Tworzy nowy StandardEncodeFilter
public StandardEncodeFilter() { }

public void doFilter(javax.servlet.ServletRequest servletRequest,
javax.servlet.ServletResponse servletResponse,
javax.servlet.FilterChain filterChain)
throws java.io.IOException,
javax.servlet.ServletException {

String contentType = servletRequest.getContentType();
if ((contentType == null) || contentType.equalsIgnoreCase(
"application/x-www-form-urlencoded")) {
translateParamsToAttributes(servletRequest, servletResponse);
}

filterChain.doFilter(servletRequest, servletResponse);
}

private void translateParamsToAttributes(ServletRequest request,
ServletResponse response) {
Enumeration paramNames = request.getParameterNames();

while (paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String [] values;
values = request.getParameterValues(paramName);
if (values.length == 1)
request.setAttribute(paramName, values[0]);
else
request.setAttribute(paramName, values);
}
}
}



Klasa odpowiedzialna za przetwarzanie formularzy umożliwiających wysyłanie plików:


public class MultipartEncodeFilter extends BaseEncodeFilter {
public MultipartEncodeFilter() { }
public void doFilter(javax.servlet.ServletRequest servletRequest,
javax.servlet.ServletResponse servletResponse,
javax.servlet.FilterChain filterChain)
throws java.io.IOException,
javax.servlet.ServletException {
String contentType = servletRequest.getContentType();
// Stosujemy filtr tylko dla kodowania wieloczęściowego
if (contentType.startsWith("multipart/form-data")){
try {
String uploadFolder = getFilterConfig().getInitParameter("UploadFolder");
if (uploadFolder == null) uploadFolder = ".";

MultipartRequest multi = new MultipartRequest(servletRequest,
uploadFolder,1 * 1024 * 1024 );
Enumeration params = multi.getParameterNames();
while (params.hasMoreElements()) {
String name = (String)params.nextElement();
String value = multi.getParameter(name);
servletRequest.setAttribute(name, value);
}
Enumeration files = multi.getFileNames();
while (files.hasMoreElements()) {
String name = (String)files.nextElement();
String filename = multi.getFilesystemName(name);
String type = multi.getContentType(name);
File f = multi.getFile(name);
// W tym miejscu w razie konieczności wykonujemy coś na pliku
}
} catch (IOException e) {
LogManager.logMessage("błąd odczytu lub zapisu pliku "+ e);
}
} // koniec if
filterChain.doFilter(servletRequest, servletResponse);
} // koniec metody doFilter()
}



Deskryptor wdrożenia konfigurujący zestaw filtrów:



StandardEncodeFilter
StandardEncodeFilter

encodefilter.StandardEncodeFilter



MultipartEncodeFilter
MultipartEncodeFilter

encodefilter.MultipartEncodeFilter

UploadFolder
/home/files




StandardEncodeFilter
/EncodeTestServlet


MultipartEncodeFilter
/EncodeTestServlet



Oprócz strategii filtru standardowego w literaturze [ALUR2004,Crawford] spotyka się również rozwiązania bazujące na własnej implementacji klasy FilterManager oraz klasy FilterChain. Nie są one jednak tak uniwersalne i przenośne jak przedstawiona strategia filtru standardowego, dlatego nie zostaną przeze mnie omówione.

Podsumowanie wzorca



Wykorzystanie wzorca Intercepting Filter wiąże się z pewnymi aspektami, z których projektant musi zdawać sobie sprawę. Jak zawsze są pozytywne oraz negatywne strony wykorzystania pewnych rozwiązań.


  • Centralizacja sterowania przy użyciu niezależnych od siebie procedur obsługi (np. autoryzacja, logowanie, szyfrowanie)

  • Poprawa wielokrotnego użycia

  • Deklaratywna i elastyczna konfiguracja




Złe strony wzorca Intercepting Filter

  • Mało wydajna wymiana danych pomiędzy filtrami




Context Object


Pisząc aplikacje często zdarza się, że wiążemy ją bardzo mocno z protokołem, w jakim pracuje. Bardzo częste są sytuacje, że w ramach całego programu wykorzystujemy obiekty HttpServletRequest. Poza brakiem możliwości zmiany protokołu komunikacyjnego takiego systemu, pojawia się bardzo duży problem z testowanie takiej aplikacji.


Należy używać wzorca Context Object w celu hermetyzacji stanu w sposób niezależny od protokołu i udostępniania go kolejnym elementom aplikacji. Trzy poniższe rysunki przedstawiają diagram klas i sekwencji wzorca.

Context Object diagram klas


Context Object dla protokołu HTTP


Context Object diagram sekwencji


Najczęstszą strategią implementacji wzorca Context Objet jest strategia kontekstu żądania w postaci mapy. Stan żądania jest przekształcany do postaci standardowej implementacji interfejsu Map, która jest przekazywana dalej. Zaletą tego rozwiązania jest jego prostota. Niestety jest też ujemna strona tego rozwiązania, a wiąże się ona ze słabym typowaniem parametrów przechowywanych w mapie, które są zrzutowanie na bazową klase Object. Poniżej przedstawiona jest przykładowa implementacja:


public class FrontController extends HttpServlet {
...
private void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, java.io.IOException {

// tworzenie obiektu RequestContext przy użyciu strategii mapy
Map requestContextMap = new HashMap(request.getParameterMap());
Dispatcher dispatcher = new Dispatcher(request, response);
requestContextMap.put("dispatcher", dispatcher);

// utworzenie instancji ApplicationController
ApplicationController applicationController = new ApplicationControllerImpl();

// przetwarzanie żądania
ResponseContext responseContext =
applicationController.handleRequest(requestContextMap);

// przetwarzanie odpowiedzi
applicationController.HandleResponse(requestContextMap,responseContext);
}
...
}




Podsumowanie


Dobre strony wzorca \textsl{Context Object}:


  • Ułatwia pielęgnację i umożliwia ponowne wykorzystanie.

  • Ułatwia testowanie - ze względu na wykorzystanie standardowych obiektów Javy możliwe jest testowanie aplikacji za pomocą standardowych narzędzi takich jak JUnit.

  • Zmniejszone ograniczenia związane ze zmianą interfejsów.



Złe strony:

  • Zmniejszona wydajność.




Composite View


Tworzenie złożonych wizualnie stron internetowych jest skomplikowaną sprawą. W przypadku kiedy tworzymy całe serwisy, wiele stron jest do siebie podobnych, lub nawet zawiera te same elementy (fragmenty szaty graficznej, system menu, itp.). Wstawianie ich na każdą stronę z osobna sprawia, że późniejsza modyfikacja tych elementów jest niezwykle pracochłonna, lub też czasami nawet nie możliwa.

Zastosowanie wzorca Composite View umożliwia konstruowanie dokumentów stron WWW poprzez złożenie elementów składowych, np. na podstawie szablonu wyglądu. Umożliwia on wprowadzenie wspólnych nagłówków, stopek, paneli nawigacyjnych w wielu miejscach dowolnego z generowanych dokumentów. W rozwiązaniach bazujących na tym wzorcu układ dokumentu wynikowego może być konfigurowany niezależnie od prezentowanej zawartości.

Composite View umożliwia również stworzenie rozwiązania w którym w prosty sposób możemy dostosować prezentowaną informację do roli użytkownika (np. kupujący, sprzedający, administrator systemu) aktualnie przeglądającego serwis WWW. Rysunek poniżej przedstawia standardową budowę strony WWW na przykładzie serwisu www.e-informatyka.pl.


Przykładowa struktura strony WWW


Poniżej wypunktowane są kluczowe czynniki, które powinniśmy rozpatrzyć w celu podjęcia decyzji o zastosowaniu wzorca Composite View:


  1. Potrzeba zastosowania wspólnych podwidoków (nagłówków, stopek, tabel), używanych w wielu miejscach.

  2. Częsta konieczność zmiany wspólnych elementów wielu widoków (np. szaty graficznej).

  3. Chęć uniknięcia powielania elementów, oraz modułowa budowa strony widoku.




Rysunek poniżej przedstawia diagram klas wzorca Composite View.

Composite View diagram klas


Opis poszczególnych elementów wzorca:

  1. Client - wybiera widok.

  2. View - reprezentuje wyświetlaną stronę. Każdy obiekt View, może być obiektem typu \textsl{SimpleView} albo CompositeView.
  3. SimpleView - reprezentuje podstawowy element składowy widoku złożonego. Nazywany jest też podwidokiem lub segmentem widoku.

  4. CompositeView - składa się z kilku obiektów typu \textsl{View}.

  5. Template - reprezentuje szablon widoku.

  6. ViewManager - używa obiektu \textit{Template} do utworzenia rozkładu strony, w której osadzona jest następnie odpowiednia zawartość. Umożliwia on niezależne zarządzanie zawartością i układem strony.




Composite View diagram sekwencji


Istnieje kilka strategii implementacji wzorca Composite View na platformie J2EE. Do najczęściej wykorzystywanych należą strategie zarządzania widokiem za pomocą:


  • komponentów Java Beans,

  • znaczników standardowych,

  • znaczników własnych,

  • przekształceń (np. XML + XSTL).



W strategii wykorzystującej pierwszej, komponenty Java Beans odpowiadają za generowanie poszczególnych widoków. Przykład strony wykorzystującej to rozwiązanie znajduje się poniżej.



<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib uri="/web-INF/corej2eetaglibrary.tld" prefix="cjp" %>

<jsp:useBean id="contentFeeder"
class="javabean.ContentFeeder" scope="request" />

<table valign="top" cellpadding="30%" width="100%">

<cjp:personalizer interest='global'>
<tr>
<td><b><c:out value="${contentFeeder.worldNews}"/></b></td>
</tr>
</cjp:personalizer>
...


Rozwiązanie wykorzystujące standardowe znaczniki JSP, jest przez wielu ekspertów [Alur2004,Crawford] uważane za bardziej "eleganckie". Związane jest to z faktem całkowitego wyeliminowania kodu Javy z głównego widoku. Taka strategia umożliwia zastosowanie podziału odpowiedzialności (ang. "separation of concern" [Sherif2000]), w którym osoba odpowiedzialna za przygotowanie szaty graficznej (np. grafik komputerowy), nie musi umieć programować a jedynie wykorzystywać elementy przygotowane przez inne osoby. Kod zamieszczony poniżej przedstawia rozwiązanie bazujące na znacznikach standardowych JSP (element jsp:include oraz @include, odpowiadają kolejno za statyczne oraz dynamiczne dołączenie zewnętrznego podwidoku).


<body>
<jsp:include page="/jsp/banner.seg" flush="true"/>
<table>
<tr>
<td>
<jsp:include page="/jsp/CompositeView/javabean/ProfilePane.jsp"
flush="true"/>
</td>
<td>
<td><%@ file="news/worldnews.html" %> </td>
</tr>
...


Strategia oparta na znacznikach własnych, jest rozszerzeniem strategii poprzedniej. Znaczniki własne są potężnym mechanizmem zarządzania zawartością i układem strony. Pomimo zwiększonego nakładu pracy programistów (proces tworzenia własnych znaczników jest złożony), jest to rozwiązanie preferowane [Alur 2004]. Zamieszczony poniżej kod przedstawia sposób wykorzystania własnych znaczników w procesie przygotowania strony.


<region:render template='/jsp/CompositeView/templates/portal.jsp'>
<region:put section='banner' content='/jsp/CompositeView/templates/banner.jsp' />
<region:put section='controlpanel' content='/templates/ProfilePane.jsp' />
<region:put section='mainpanel' content = '/templates/mainpanel.jsp' />
<region:put section='footer' content='/templates/footer.jsp' />
</region:render>


trategia bazująca na przekształceniach, to z reguły rozwiązania bazujące na XML'u oraz XSLT. Jest to rozwiązanie o największych możliwościach, ale jednocześnie najmniejszej efektywności. Widok może być wielokrotnie transformowany zanim zostanie przekazany klientowi, a każda z transformat może być niezależnie wymieniana na inną. Rozwiązanie takie jest nieocenione, kiedy z naszej aplikacji korzysta wielu klientów o różnych możliwościach (np. przeglądarka internetowa, urządzenia PDA, telefony komórkowe, itp.). Powstało wiele środowisk wspierających taką strategie np. Cocoon (http://cocoon.apache.org/). Idea działąnia przekształceń została przedstawiona na poniższym rysunku.

Composite View strategia z wykorzystaniem przekształceń


Podsumowanie



Wprowadzenie wzorca \textsl{Composite View} pociąga za sobą pewne konsekwencje, z których powinniśmy zdawać sobie sprawę. Oprócz pozytywnych aspektów zastosowania tego rozwiązania istnieją również słabe strony. Do plusów niewątpliwie moglibyśmy zaliczyć:


  • Poprawę modularności i możliwość ponownego wykorzystania kodu.

  • Możliwość dodania kontroli opartej na regułach. Do takich reguł może należeć rola użytkownika lub pewne ustawienia systemowe.

  • Ułatwienie pielęgnacji kodu.



Istnieje jednak kilka negatywnych aspektów:

  • Utrudnienie zarządzania kodem. Związane to jest z możliwością powstawania błędów wyświetlania podczas łączenia kilku elementów w jednym widoku.

  • Zmniejszenie wydajności - związane z koniecznością dynamicznego tworzenia widoku na żądanie klienta.



Zakończenie


Dokument ten stanowi jedynie wstęp do tematyki wzorców projektowych warstwy prezentacji platformy J2EE. Pokazuje jednak jak ważną rolę mogą one odegrać w procesie projektowania aplikacji. Pozwalają zredukować koszty wytworzenia systemu, dzięki zastosowaniu sprawdzonych rozwiązań. Dzięki wzorcom możemy także efektywniej komunikować się o obrębie zespołów projektowych.

Nie należy jednak zapominać, że wzorzec projektowy stanowi jedynie szablon pewnego rozwiązania. Szablon ten następnie może być zaimplementowany za pomocą kilku strategii. Starałem się wraz z omawianiem każdego wzorca przejście od zdefiniowania problemu jaki nas dotyczy, przez wybranie ogólnego rozwiązania (wzorca projektowego), aż do jego szczegółowej implementacji będącej strategią.

Należy zdawać sobie jednak sprawę, że wykorzystywanie wzorców projektowych pomimo niezliczonej ilości korzyści generuje pewien narzut. Narzutem tym może być zwiększona liczba linii kodu, jaki należy wpisać, może być nim również zwiększony czas wykonywania się naszego programu.

Bibliografia



[ALUR2004] - D.Alur, J.Crupi, D.Malks, "Core J2EE Wzorce projektowe"
[Crawford] - W.Crawford, J.Kaplan, "J2EE Stosowanie wzorców projektowych"
[Sherif2000] - M.Y.Sherif, H.H.Ammar, "Pattern-Oriented Analysis and Design: Composing Patterns to Design Software Systems"

No comments: