e-Informatica Software Engineering Journal Komponentowe podejście do projektowania i implementacji aplikacji internetowych

Komponentowe podejście do projektowania i implementacji aplikacji internetowych

Zbigniew Fryźlewicz,  Marek Kwiecień
Wydziałowy Zakład Informatyki, Wydział Informatyki i Zarządzania,  Politechnika Wrocławska
z.fryzlewicz@ci.pwr.wroc.pl  kwiecienm@o2.pl
Streszczenie

W rozdziale przedstawiono komponentowe podejście do projektowania aplikacji internetowych. Zaprezentowano architekturę trzywarstową optymalizowaną pod kątem uproszczenia budowy i utrzymania dowolnego serwisu internetowego. Dodatkowo, przedstawione rozwiązanie jest wydajne dzięki optymalnemu dostępowi do bazy (pod względem ilości wykonywanych zapytań, a co za tym idzie – generowanego ruchu pomiędzy klientem a serwerem) oraz użyciu mechanizmów cache

1. Wstęp#

Budowanie aplikacji internetowych to dzisiaj modne ale dość rozległe zagadnienie. Dzięki sporej liczbie istniejących i coraz to nowszych technologii istnieje w tej dziedzinie dużo przeróżnych podejść i propozycji rozwiązań. Jednym z nich jest podejście komponentowe i w połączeniu z technologiami opartymi na Javie i XML jest ono reprezentowane w tym rozdziale. Według autorów, poza ogólnymi hasłami, trzy istotne cechy czynią podejście komponentowe atrakcyjnym dla projektantów aplikacji internetowych. Są to:

  • powtórne wykorzystanie komponentów w nowym przedsięwzięciu projektowym
  • redukcja czasu wdrożenia nowego projektu
  • minimalizacja kosztów konserwacji oprogramowania

Budowanie aplikacji, które mają być stabilne, wydajne czy też bezpieczne wymaga właściwego stosowania istniejących technologii. Na bazie technologii Javy powstało wiele tzw. wzorców projektowych, które są zaleceniami i wskazówkami jak rozwiązywać pewne typowe, cząstkowe problemy i stopniowo budować całą aplikację. Opisywana praca opiera się częściowo na takim podejściu. Cała aplikacja jest zdekomponowana na trzy warstwy, które implementują wybrane wzorce. Dokładniej, aplikacja może być dowolna. Co ona aktualnie zawiera, jak działa wewnętrznie i zewnętrznie jest w pełni konfigurowalne za pomocą technologii opartych o XML. W dalszym ciągu jednak kluczową rolę odgrywa komponentowość rozwiązania i wynikłe z niej cechy aplikacji.

1.1. Architektura trzywarstwowa#

Podstawą proponowanego rozwiązania jest architektura trzywarstwowa (rysunek 1) czyli podział na:

  • warstwę danych (baza danych + dostęp do niej)
  • warstwę biznesową
  • oraz warstwę prezentacji

fig1.png

Rysunek 1. Architektura trzywarstwowa

Taka architektura sprzyja komponentowości – zapewnia rozdział pomiędzy logiką i prezentacją, które można zamknąć w konkretnych pakietach-komponentach. Oznacza to, że warstwy biznesowa i danych będą faktycznie znajdowały się tylko w komponentach – to one przejmują na siebie ciężar logiki biznesowej. Mechanizmy zarządzające tymi komponentami oraz wizualizacja ich funkcjonalności znajdują się w warstwie prezentacji i pełni ona funkcję kontrolera do warstw niższych.

1.2. Warstwa danych#

Warstwa danych może się składać z wielu różnego rodzaju elementów. Przykładowo może to być zestaw plików podzielony na katalogi lub też „konwencjonalna” baza danych.Jeśli mówimy o bazie danych jako warstwie danych, to należy wspomnieć jak ważne jest odpowiednie jej zamodelowanie – wybranie odpowiedniego systemu zarządzania, czy implementacja w języku SQL. Czasem zagadnienie to bywa marginalizowane przez projektantów i programistów. Tymczasem niewydajna struktura tej warstwy bezpośrednio i radykalnie rzutuje na wydajność warstw wyższych [MCLA2002].

1.3. Warstwa biznesowa#

Warstwa biznesowa odpowiada za logikę biznesową budowanej aplikacji oraz za dostęp do danych. Jest istotna z punktu widzenia optymalizacji, gdyż jest pierwszym tzw. ,,wąskim gardłem każdej aplikacji. Jeśli chcemy budować aplikacje większych rozmiarów, powinno się rozważyć, czy w tej warstwie nie użyć EJB [MCLA2002].Oczywiście sposób implementacji poszczególnych warstw w samych komponentach jest dowolny (o ile komponent spełnia założoną z góry funkcjonalność), ale w opisywanym rozwiązaniu preferowany jest podział warstwy biznesowej jak na rysunku 2.:

fig2.png

Rysunek 2. Warstwa biznesowa zdekomponowana na trzy podwarstwy

Każdy komponent (mając warstwę biznesową) posiada swoją klasę Fasada (ang. Facade) – jednolity dostęp do obiektów biznesowych, oraz klasę Dostęp do danych (ang. Data Access, DAO) – odpowiedzialną za dostęp do warstwy danych. Pomiędzy nimi może istnieć dowolna ilość klas reprezentujących akcje biznesowe.

1.4. Warstwa prezentacji#

Kontroler jest centralnym serwletem, który odbierając i interpretując żądania HTTP wybiera widoki z warstwy prezentacji do wyświetlenia w przeglądarce klienta. Wybór jest kontekstowy – na podstawie odebranych parametrów, stanu sesji, etc. Takie podejście jest implementacją wzorca MVC (ang. Model View Controller – Model Widok Kontroler) [STOL2001], gdzie modelem są warstwy biznesowa i danych, a warstwa prezentacji odpowiada za budowanie widoków.Podejście komponentowe wymusza napisanie platformy, nazwijmy ją aplikacją sterującą, na której komponenty będą uruchamiane. Jednoczenie chcemy, żeby komponenty były w łatwy sposób zarządzalne – najlepiej z poziomu plików – na przykład XML. Jeśli mowa o aplikacjach internetowych, to taki zestaw plików może nam identyfikować cały serwis – moglibyśmy w nim mieć informacje o tym w jaki sposób ułożone są widoki względem siebie oraz jakie akcje są wykonywane podczas przejść pomiędzy stronami, innymi słowy definiują diagram przejść pomiędzy stronami.

Pozostaje pytanie czym jest komponent. Dość trudno o jednoznaczną, bezpośrednią i powszechnie akceptowaną definicję tego terminu. Zwykle komponenty definiuje się poprzez podanie ich właściwości i podkreślenie różnic w stosunku do właściwości obiektów. Według [SZYP2001] komponenty charakteryzują się następującymi właściwościami:

  • komponent jest niezależnie upowszechnianym elementem montażowym,
  • komponent jest jednostką zestawienia dokonywanego przez osoby postronne,
  • komponent nie ma żadnego trwałego stanu.

W przeciwieństwie do cech charakteryzujących komponenty właściwości wyróżniające obiekty są następujące:

  • obiekt jest jednostką konkretyzacji; ma niepowtarzalną tożsamość,
  • obiekt ma stan – może to być stan trwały,
  • obiekt obudowuje (ukrywa) swój stan i zachowanie,

W rozważanym przypadku aplikacji internetowej komponent odpowiada logicznie za pewną całość – za aktywną część serwisu, na przykład za obsługę wiadomości, czy forum użytkowników. Mówiąc obrazowo – komponenty możemy porównać do klocków, z których budujemy aplikację.

2. Rozwiązania#

Kwestią zasadniczą jest odpowiedź na pytanie o funkcjonalność, jaką powinien udostępniać komponent.W aplikacjach internetowych podstawową akcją jest przetwarzanie danych w odpowiedzi na żądania użytkownika. Żądania mogą być proste – wyświetlanie pojedynczej strony WWW, lub złożone, w postaci np. wielokrokowego formularza. Część komponentu odpowiedzialna z wizualizację zwracanych danych nazwiemy widokiem. Dodatkowo, komponent powinien mieć możliwość wykonywania akcji biznesowych. Niech odbywa się to poprzez komendy. Akcja biznesowa może być prostą np. wyzwalać odczyt pojedynczych danych z jakiejś bazy, lub złożoną w postaci transakcji bazodanowej i zwrotu potwierdzenia jej realizacji. Trzecim bardzo ważnym elementem jest kontekst komponentu, na który powinny składać się parametry przekazane w żądaniu HTTP, parametry sesji oraz inne pochodzące na przykład z plików konfiguracyjnych implementowanego serwisu internetowego.

fig3.png

Rysunek 3. Komponent i jego interakcje z aplikacją sterującą

Diagram z rysunku 3. przedstawia komponent, do którego aplikacja sterująca ma dostęp poprzez interfejsyView oraz Command. Oczywiście wszelkie żądania HTTP odbywają się poprzez tę aplikację, i to na podstawie przekazanych parametrów otrzymuje ona informacje, które widoki jakich komponentów ma wyświetlić. Dalsze informacje o procesie tworzenia wynikowego dokumentu opisano w punkcie 2.5.

2.1. Widoki#

Komponent może mieć wiele różnych widoków.Wspólny interfejs, który implementować będą widoki musi być prosty a jednocześnie uniwersalny. Nie należy zapominać, że taki interfejs (rysunek 4) narzuca później sposób jego implementacji, więc w chwili jego definiowania należy go wyjątkowo dokładnie rozważyć.

fig4.png

Rysunek 4. Diagram klas widoków

Interfejs z rysunku 4. udostępnia jedną metodę – render(), która zwraca obiekt typu StringBuffer. Takie rozwiązanie pozostawia pewną dowolność. W zwracanym obiekcie może być fragment dokumentu XML, HTML etc. Dalsze przetwarzanie takiego “fragmentu” nie jest w momencie definiowania interfejsu w żaden sposób przesądzone.Rysunek 5. przedstawia diagram sekwencji dla pewnego przypadku, gdy dane z bazy, pobierane w postaci obiektu VO (ang. Value Object), wynik operacji AccessBean getSomeData(), są serializowane początkowo na strukturę XML, a następnie poddawane transformacji przy pomocy związanego pliku XSLT. Wynikiem jest dokument w formacie HTML. Dalsze zwiększenie elastyczności rozwiązania to dynamiczne, kontekstowe wybieranie pliku z transformacją XSLT.

fig5.png

Rysunek 5. Diagram sekwencji dla konkretnego przypadku implementacji metody render()

Używając bardziej zaawansowanego serwera baz danych informację można przechowywać bezpośrednio w postaci XML lub, nawet przy natywnych bazach relacyjnych, zapytania i odpowiedzi otrzymywać także jako dokumenty XML.Najczęściej poszczególne widoki będą miały dostęp do obiektów biznesowych reprezentujących logikę systemu.

2.2. Komendy#

Podobnie jak w przypadku widoków, także dla komend należy ustalić jeden prosty i uniwersalny interfejs (rysunek 6). Niech akcję biznesową reprezentuje metoda execute(), która po wykonaniu zwraca obiekt typuCommandResponse zawierający informacje, czy wykonanie komendy powiodło się, czy też nie. W przypadku niepowodzenia może być potrzebne przekierowanie na stronę z opisem błędu. Poprawne wykonanie komendy powoduje przeniesienie do innej, zwykłej strony. Informacje o komendach są zapisane w pliku konfiguracyjnym i jest to jedyne miejsce ewentualnej modyfikacji diagramu przejść, co jest zaletą rozwiązania. Plik opisuje przejścia między stronami serwisu – czyli de facto kontekstową realizację komend. Przykładowo, jeśli składową aplikacji internetowej jest obsługa forum użytkowników, to po wykonaniu akcji dodania odpowiedzi na forum przeniesienie nastąpi do strony pokazującej dodany wątek.Dokładniejsze informacje o procesie renderowania i wykonywania komend zamieszczono w punkcie 2.5.

fig6.png

Rysunek 6. Diagram klas komend

Komendy, tak samo jak widoki, mogą korzystać z pewnej liczby obiektów biznesowych reprezentowanych przez np. klasy EJB. Również podobnie jak w przypadku widoków, w komponencie może ich być dowolna liczba.Komendy to klasy wchodzące w skład warstwy prezentacji.

2.3. Komponent – widok implementacyjny#

Rozważmy teraz implementację komponentu. Podzielmy klasy komponentu na zestaw pakietów:

  • view
  • command
  • vo
  • ejb
  • dao

Gdzie vo, to klasy typu Value Object – proste ziarna Java (ang.Java beans) z metodami getXXX() orazsetXXX() odzwierciedlające strukturę warstwy danych – takie obiekty są zwracane przez klasy pakietu dao.

Pakiety view oraz command zostały już opisane, odpowiednio w p. 2.1. oraz 2.2. Rozpatrzenia wymaga pakietejb, w którym tworzymy warstwę biznesową komponentu.

Warstwa biznesowa to serce każdego komponentu. Stosując nowe technologie chcemy, by była wydajna, ale EJB nie jest najprostsze w użyciu. Mając kilka obiektów biznesowych wywoływanie ich metod z kodu klienta może nastręczyć wielu kłopotów. Ustalmy zatem, że do obiektów biznesowych – będących dowolnymi klasami EJB będziemy mieli dostęp poprzez klasę Facade [MARI2002], która konkretnie zawsze będzie ziarnem Java typu SessionBean. Nadal jest to klasa EJB, więc w celu dalszego uproszczenia kodu klienta dodajmy jeszcze jeden obiekt, który opakowuje metody fasady w taki sposób, że odwołujemy się do nich w taki sposób jak do metod lokalnych [STOL2001]. Schematycznie powyższy tok rozumowania przedstawia rysunek 7.

fig7.png

Rysunek 7. Dalsze uszczegółowienie warstwy biznesowej

Jeśli logika biznesowa komponentu jest na tyle prosta, że nie będzie specjalistycznych klas biznesowych – wtedy fasada miałaby dostęp bezpośrednio do klas DAO. Alternatywnym rozwiązaniem może być obowiązkowe tworzenie nawet pustych klas.

2.4. Warstwa prezentacji – zarządzanie komponentami#

Po uścisleniu roli i funkcjonalności komponentów należy jeszcze rozważyć zarządzanie nimi, czyli aplikacją sterującą. Jest ona umieszczona w warstwie prezentacji i ma dostęp do serii plików konfiguracyjnych komponentów. Istotne decyzje projektowe to rodzaj i zawartość tych plików.Z wcześniejszych rozważań wynika potrzeba istnienia co najmniej dwóch plików. Pierwszy, zawierający diagram przejść pomiędzy stronami serwisu – nazwijmy go diagram.xml oraz drugi, zawierający dane w jaki sposób widoki są ułożone na stronach – nazwijmy go page.xml. Nieodzowne jest jeszcze istnienie plików zawierających szablony stron (layout.xml) oraz ogólną konfigurację serwisu (config.xml).

2.4.1. CONFIG.XML#

Zacznijmy od najprostszego pliku – config.xml. W części przedstawionej na Listingu 1 zawiera on podstawowe zmienne opisujące serwis, tj. lokalizację pozostałych plików konfiguracyjnych, ścieżki do katalogów z plikami XSL, informacje o włączeniu/wyłączeniu mechanizmu cache.

<?xml version="1.0"?>
<config>
  <item name="DIAGRAM_PATH"
    value="d:/t4/webapps/wulf/xml/diagram.xml"/>
  <item name="PAGE_PATH"
    value="d:/t4/webapps/wulf/xml/page.xml"/>
  <item name="LAYOUT_PATH"
    value="d:/t4/webapps/wulf/xml/layout.xml"/>
  <item name="GLOBAL_XSL_PATH"
    value="d:/t4/webapps/wulf/xml/wulf.xsl"/>
  <item name="HTML_PATH"
    value="d:/t4/webapps/wulf/"/>
  <item name="XSL_ROOT_PATH"
    value="d:/t4/webapps/wulf/"/>
  <item name="CACHE_ENABLED"
    value="true"/>
</config>
Listing 1. Przykład pliku config.xml

Dodatkowo można w nim umieścić umieścić pewne zmienne dla komponentów, którymi chcielibyśmy globalnie zarządzać, na przykład ścieżkę do katalogu dla komponentu obsługującego wgrywanie plików na serwis, czy ilość dni, po których wiadomość przechodzi do archiwum.Przy implementacji klasy do zarządzania tym plikiem dobrze jest posłużyć się wzorcem projektowym Singleton[STOL2001]. Jest wtedy gwarancja istnienia w systemie tylko jednej instancji takiej klasy i dostępu do tej instancji z całej aplikacji.

2.4.2. LAYOUT.XML#

Zadaniem pliku layout.xml (Listing 2) jest podział strony (reprezentowanej przez element layout) na komórki rozmieszczone w wierszach (elementy td) i kolumnach (elementy tr). W tych komórkach będą później umieszczane widoki. Każdy element layout, td, tr ma unikatową wartość atrybutu id, co jednoznacznie identyfikuje każdy element i pozwala na kojarzenie z właściwym widokiem.

<?xml version="1.0" ?>
<layouts>
  <layout
   id="init_layout" width="100%">
    <tr><td id="body"/></tr>
  </layout>
  <layout id="main_layout" width="729" border="0">
   <tr><td colspan="3" width="729" id="head"/></tr>
   <tr>
     <td width="154" valign="top" id="left"/>
     <td width="450" valign="top" id="body"/>
     <td width="125" id="right"/>
   </tr>
   <tr><td colspan="3" width="729" id="copyright"/></tr>
  </layout>
</layouts>
Listing 2. Przykład pliku layout.xml

fig8.png

Rysunek 8. Przykładowa wizualizacja pliku z układami serwisu

2.4.3. PAGE.XML#

W pliku page.xml (Listing 3) umieszczono informację o wyglądzie poszczególnych stron serwisu. Korzysta on z pliku layout.xml, by określić jak elementy są ułożenie na stronie. Stronę definiuje zestaw elementów tdodpowiadających elementom td z wybranego wyglądu strony – mają taki sam element id. Do każdej komórki wkładamy widoki, które mają parametry class – klasa widoku oraz cached i cacheTimeout do sterowania mechanizmami umieszczania widoków w pamięci podręcznej. Można tu zastosować dodatkowo mechanizm dziedziczenia stron, w celu definiowania stałych elementów takich jak menu, stopka czy nagłówek. Wtedy definiujemy najpierw stronę, która nie pokrywa w pełni elementów wyglądu. Strona dziedzicząca (parametrextends) po takiej stronie ma za zadanie pokryć pozostałe elementy wyglądu.

<?xml version="1.0" encoding="ISO-8859-2"?>
<pages>
  <page id="common" layout="main_layout">
    <td id="head">
      <view 
       class="com.padlock.engine.view.HTMLView" cached="true"
       cacheTimeout="1000">
        <param name="html" value="header.html"/>
      </view>
    </td>
    <td id="left" valign="top" align="left">
      <view
       class="com.padlock.component.newsletter.view.SubscribeView"
       cached="false">
        <param name="xsl" value="newsletter/subscribe.xsl"/>
      </view>
    </td>
    <td id="right">
      <view
       class="com.padlock.component.adserver.view.BannerView"
       cached="false">
        <param name="xsl" value="adserver/banner.xsl"/>
        <param name="campaign_name" value="test"/>
      </view>
    </td>
    <td id="copyright">
      <view
       class="com.padlock.engine.view.HTMLView" cached="true"
       cacheTimeout="1000">
        <param name="html" value="copyright_note.html"/>
      </view>
    </td>
  </page>
  <page id="company_news_list"
   layout="main_layout" extends="common"
   title="WULF - Company News List">
    <td id="body">
      <view
       class="com.padlock.component.news.view.NewsListView"
       cached="false">
        <param name="xsl" value="news/news_list.xsl"/>
        <param name="kind_id" value="1"/>
      </view>
    </td>
  </page>
</pages>
Listing 3. Przykład pliku page.xml

2.4.4. DIAGRAM.XML#

W pliku diagram.xml (Listing 4) umieszczono informacje o komendach dostępnych na stronach serwisu (same strony są opisane w pliku page.xml). Na każdej stronie, do której odwołanie odbywa się poprzez parametr id, definiujemy zestaw komend opisanych szeregiem parametrów. Parametr name to nazwa komendy – ta nazwa będzie brała udział w procesie wyświetlania strony. Parametr class – to nazwa klasy komendy, której metodaexecute() będzie wykonywana. Komendy posiadają jeszcze elementy result, które zawierają nazwy stron jakie mają zostać wyświetlone po pomyślnym jak i niepomyślnym wykonaniu komendy.

<?xml version="1.0" ?> 
<diagram>
  <page id="company_news_list">
    <command name="subscribe"
     class="com.padlock.component.news.command.SubsrcibeCommand">
      <result name="success" page="company_news_list"/>
      <result name="failure" page="init"/>
    </command>
  </page>
  <page id="company_news">
    <command name="add_comment"
     class="com.padlock.component.news.command.AddCommentCommand">
      <result name="success" page="company_news_list"/>
      <result name="failure" page="init"/>
    </command>
  </page>
</diagram>
Listing 4. Przykład części pliku diagram.xml

2.5. Proces wyświetlania stron#

Proces wyświetlania strony rozpoczyna się w momencie otrzymania przez platformę sterującą parametrów żądania HTTP. Niezbędnym parametrem jest bądź cmd (ang. Command – Komenda) – nazwa komendy, która ma zostać uruchomiona (informacje o komendzie znajdują się w pliku diagram.xml opisanym w punkcie 2.4.4) bądź pt (ang. Page Template – Szablon Strony) – nazwa szablonu strony do uruchomienia (informacje o tym szablonie są w pliku page.xml opisanym w punkcie 2.4.3). Jeśli nie ma żadnego z nich – wyświetlana jest domyślna (na przykład główna) strona serwisu.Parametry są dalej przekazane do kontekstu, skąd widoki mają do nich dostęp. Na podstawie parametru ptplatforma sterująca wybiera szablon strony oraz jego ułożenie (ta informacja znajduje się w pliku layout.xmlomówionym w punkcie 2.4.2). Teraz dla każdego wiersza i dla każdej kolumny ułożenia wyświetla widoki – wykonuje metodę render(). Jeśli widok posiada parametr cache, wtedy sprawdzane jest, czy znajduje się on w pamięci podręcznej i czy przypadkiem nie nastąpiło przekroczenie limitu czasu w niej przetrzymywania. Jeśli widok nie znajduje się w pamięci albo jeśli został przekroczony czas jego przetrzymywania, to jest ponownie tworzony i ponownie wykonywana jego metoda render(). Wyniki przechowujemy w strukturze DOM po czym, po wyświetleniu ostatniego widoku następuje finalna transformacja XSL do dowolnego formatu wynikowego.

Aby przyspieszyć proces wyświetlania stron można zastosować mechanizm cache – w takim kontenerze trzymane byłyby poszczególne widoki, które należy odświeżyć po czasie ustalonym na poziomie plików konfiguracyjnych.

fig9.png

Rysunek 9. Diagram sekwencji renderowania stron

Wykonywanie komend wygląda bardzo podobnie z tym wyjątkiem, że w żądaniu HTTP przychodzi informacja o komendzie jaka ma zostać wywołana. Na podstawie wyników jej wykonania wybierana jest strony do pokazania i dalej proces przebiega jak wyżej.

3. Podsumowanie#

Dzięki komponentowemu podejściu do projektowania aplikacji internetowych zyskujemy na kilku płaszczyznach:

  • kosztowej – z wdrożenia na wdrożenie zmniejsza się koszt dzięki rozbudowie architektury i bazy komponentów
  • projektowej – mając za sobą kilka gotowych wdrożeń przeprowadzanie nowych jest często kwestią specyfikowania wymagań
  • implementacyjnej – zyskujemy łatwo rozwijalną architekturę i podział serwisów na łatwe do zarządzania części (wszystko w myśl zasady dziel i rządź)

Podział na komponenty nie jest oczywiście niczym nowym. Materiał przedstawiony w tym rozdziale miał na celu odświeżenie spojrzenia na ten problem poprzez zastosowanie go w aplikacjach internetowych z wykorzystaniem nowych technologii i przedstawiając kompleksowe rozwiązanie.

Oprócz prezentacji danych istnieją jeszcze dwa zagadnienia – zarządzanie danymi i zarządzanie konfiguracją. Aby zarządzać danymi należałoby zbudować interfejs posługując się rozwiązaniem przedstawionym w rozdziale. W tym celu wymagane byłoby stworzenie komponentu do obsługi formularzy oraz rozszerzające funkcjonalność warstwy biznesowej o metody edycji i usuwania danych. Analogicznie zarządzanie konfiguracją, to napisanie aplikacji udostępniającej interfejs graficzny do edycji plików layout.xml, page.xml i diagram.xml.

Warte zauważenia jest jeszcze i to, że komponenty można rozwijać metodą przyrostową i budować na zasadach prostego prototypowania.

Bibliografia#

[GoF1994] E. Gamma, R. Helm, R. Johnson i J. Vlissides, Design Patterns – Elements of Reusable Software, Addison Wesley, 1994.
[MARI2002] F. Marinescu, EJB Design Patterns, John Whiley& Sons, Inc., 2002.
[MCLA2002] B. McLaughlin, Building Java Enterprise Applications, Volume 1: Architecture, O’Reilly & Associates, Inc., 2002.
[STOL2001] S. Stelting i O. Maassen, Applied Java Patterns, Prentice Hall PTR, 2001.
[SZYP2001] C. Szyperski, Oprogramowanie komponentowe. Obiekty to za mało, WNT, 2001.

©2015 e-Informatyka.pl, All rights reserved.

Built on WordPress Theme: Mediaphase Lite by ThemeFurnace.