SYSINFO

grafika dekoracyjna

Analizy i publikacje

Pliki do pobrania:

BMU20.pps (prezentacja PowerPoint), BMU20.zip (projekt pakietu i kod źródłowy).

Biblioteka BMU

Istotną niedogodnością metodyczną pojawiającą się w zintegrowanych środowiskach programistycznych jest nadmierne znaczenie, jakie projektanci tych środowisk nadali zagadnieniom dostępu do baz danych. Dotyczy to zarówno komponentów integrujących aplikację z relacyjnymi bazami danych, jak i komponentów realizujących obsługę odpowiednich elementów graficznego interfejsu użytkownika – komponentów, które umożliwiają użytkownikowi wizualną edycję danych. Sytuacja ta, niezależnie od zalet tego typu środowisk programistycznych, ogranicza w pewnym stopniu ich potencjalne możliwości. Zmusza bowiem programistów do łączenia funkcji związanych z przetwarzaniem danych, z funkcjami obsługującymi interfejs użytkownika. Dotyczy to najczęściej tych fragmentów kodu źródłowego programu, które są odpowiedzialne za obsługę okien formularzy edycyjnych. Kod źródłowy programu jest wówczas dosyć nieczytelny, przez co uruchamianie i późniejsza konserwacja programu są w znacznym stopniu utrudnione.
Środowisko programistyczne C++ Builder™, podobnie zresztą, jak opracowane wcześniej w firmie Borland środowisko Delphi™, jest bardzo popularne wśród programistów i firm informatycznych zajmujących się wytwarzaniem oprogramowania. Oba środowiska programistyczne posługują się rozbudowaną biblioteką komponentów VCL (ang. Visual Component Library), która znacznie przyspiesza i ułatwia tworzenie aplikacji działających w środowiskach graficznych systemów operacyjnych. Rrzeba stwierdzić, że wspomniana wcześniej funkcjonalność tychże środowisk zintegrowanych odpowiedzialna za komunikację z bazami danych została bardzo dobrze zaprojektowana i to ona właśnie zadecydowała o ich dużej popularności. Niezależnie od tego faktu, narzucony przez twórców środowiska model aplikacji jest bardzo odległy od rozwijanych i wdrażanych w ostatnich latach obiektowych metod analizy i projektowania systemów informatycznych, co jest istotą niedogodności, o których tu mowa.
Powstaje zatem poważna przeszkoda w stosowaniu środowiska zintegrowanego C++ Builder™ w realizacjach tych projektów, w których oprogramowanie wytwarza się z zastosowaniem metodyk obiektowych. Problem polega w głównej mierze na braku możliwości sprzężenia obiektowego modelu systemu informatycznego z jego implementacją, a właściwe z tą częścią implementacji, która realizuje funkcje komunikacji z bazą danych i edycją jej zawartości. Problem ten najbardziej uwidacznia się w przypadku, w którym w procesie wytwarzania systemów informatycznych korzysta się z oprogramowania narzędziowego typu CASE (ang. Computer Aided Software Engineering), szczególnie zaś w przypadku posługiwania się udostępnianymi przez to oprogramowanie generatorami kodu źródłowego.
W ramach projektu BMU (projekt prowadzony częściowo w ramach badań finansowanych przez Ministerstwo Nauki)  podjęto próbę rozwiązania opisanego powyżej problemu dla platformy zintegrowanego środowiska programistycznego C++ Builder™. W ramach prac nad artykułem opracowane zostały projekt i implementacja biblioteki komponentów nazwanej przez autorów skrótem BMU (od ang. Business Model Utility). Biblioteka ta umożliwia implementację w wymienionym środowisku, oprogramowania, którego projekt powstał z zastosowaniem metodyki obiektowej, np. metodyki RUP™(ang. Rational Unified Process) oraz związanych z tą metodyką programów narzędziowych typu CASE.

Analiza problemu i jej wyniki

Podstawowe pytanie, jakie należy zadać rozważając możliwości rozszerzenia środowiska Borland C++ Builder™ o elementy integrujące jego koncepcję z koncepcją metodyki obiektowej RUP™, dotyczy ustalenia sposobu implementacji, który zagwarantuje pełne wykorzystanie sporych przecież możliwości biblioteki VCL. Szczególnie dotyczy to tej funkcjonalności biblioteki, która znajduje się w warstwie komunikacji aplikacji z bazą danych. Aby móc odpowiedzieć na tak postawione pytanie, należy zastanowić się nad kilkoma aspektami rozważanej integracji.
Pierwszy aspekt dotyczy pokonania różnic koncepcyjnych pomiędzy podejściem obiektowym i strukturalnym, które to podejście de facto zostało narzucone programistom przez twórców środowiska, pomimo, iż sama biblioteka VCL stanowiąca jego trzon zrealizowana została z zastosowaniem technik obiektowych. Sięgając głębiej należy zauważyć, że przyczyna tych różnic leży w rozbieżnościach pomiędzy schematem obiektowym, który jest istotą samego podejścia obiektowego, a schematem relacyjnym, na którym oparto koncepcję stosowanych nadal bardzo powszechnie relacyjnych baz danych.
Drugi aspekt problemu związany jest z zaprojektowanymi przez twórców biblioteki VCL mechanizmami integracji aplikacji z bazami danych i potencjalnymi możliwościami wykorzystania ich funkcjonalności. Innymi słowy chodzi o to, by nie powtarzać wykonanej już raz pracy, a w szczególności o to, by móc uchwycić precyzyjnie miejsce w strukturze klas biblioteki VCL pozwalające na pobranie danych niezbędnych do odtworzenia schematu obiektowego, który wynika z projektu budowanej aplikacji. Odtworzenie schematu obiektowego klas realizujących zasadnicze funkcje aplikacji jest bowiem najważniejszym elementem integracji środowiska programistycznego ukierunkowanego na współpracę z bazami relacyjnymi, z metodyką obiektową, taką jak np. metodyka RUP™.
Trzecim elementem rozważań podjętych przez autorów niniejszej pacy jest techniczny aspekt realizacji wspomnianego mechanizmu odtwarzania struktury klas, których stan wyrażony jest przez wartości atrybutów zapisane w relacyjnej bazie danych. W warstwie bardziej technologicznej oczywiste jest tutaj wybranie przewidzianej przez twórców środowiska C++ Builder™ drogi wprowadzania doń własnych rozszerzeń poprzez implementację dodatkowych komponentów. W warstwie koncepcyjnej, należy ustalić, jakie to powinny być komponenty i jakie funkcje powinny realizować.

Koncepcja biblioteki BMU

Przyjęta koncepcja rozwiązania problemu dotyczącego rozbieżności pomiędzy schematami: relacyjnym i obiektowym opiera się na trzech założeniach:
1) W kwestii odzwierciedlania relacji uogólnienia można pozostawić projektantowi aplikacji możliwość zastosowania dowolnego podejścia: bądź to spłaszczenia kraty dziedziczenia, bądź jej dokładnego odwzorowania w bazie danych. Możliwe jest także zastosowanie podejścia pośredniego.
2) Odwzorowanie typu klasy powinno nastąpić poprzez jawne skojarzenie typu klasy z nazwą tabeli lub zbiorem krotek relacji będących wynikiem określonej projekcji i (lub) selekcji, względnie złączenia.
3) Problem gromadzenia instancji klas najlepiej rozwiązać poprzez zastosowanie uniwersalnych agregatorów, tj. kolekcji klas pozwalających na gromadzenie odnośników do abstrakcyjnej klasy obiektu bazowego – klasy-korzenia mogącej być przodkiem wszystkich innych klas w budowanej strukturze.
Aby najpełniej wykorzystać możliwości biblioteki VCL ułatwiające programiście konstruowanie warstwy komunikacji z bazą danych, trzeba skorzystać z komponentu, który w strukturze klas usytuowany jest możliwie jak najwyżej, a jednocześnie posiada odpowiednie funkcje. Chodzi o to, żeby zachowując pełną funkcjonalność nie uzależniać jednocze-śnie implementacji przyszłej biblioteki od szczegółów związanych z obsługą konkretnych standardów komunikowania się aplikacji z bazami danych. Rolę takiego uogólnienia w bibliotece VCL pełni abstrakcyjna klasa TDataSet. Klasa ta reprezentuje dowolny zbiór krotek relacji i jest całkowicie niezależna od źródła, z którego pochodzą dane. Wszystkie wyspecjalizowane klasy reprezentujące tabele, zapytania, wyniki wykonani procedur SQL składowanych w bazie lub zbiory rekordów rezydujące w pamięci są potomkami tej właśnie klasy. Z tego względu to właśnie z poziomu klasy TDataSet najlepiej pobierać wartości atrybutów podczas odtwarzania schematu obiektowego utrwalonego w bazie danych.

 

Mechanizmy utrwalania i odtwarzania obiektów na podstawie danych zapisanych w różnej postaci w plikach lub bazach danych – generalnie chodzi o zapis na nośnikach pamięci masowej, który to zapis różni się o zapisu w pamięci operacyjnej – są już dobrze znane. Część z tych mechanizmów utrwalono w ogólnie przyjętych i stosowanych szablonach projektowania i implementacji, czyli w tzw. wzorcach projektowych (ang. design patterns). Jednym z takich mechanizmów jest mechanizm tzw. fabryki klas (ang. class factory), który również utrwalono we wspomnianych wzorcach projektowych. Wzorzec ten opisuje działanie klasy posiadającej funkcje pozwalające na wywoływanie odpowiednich konstruktorów klas w zależności od danych zapisanych w pliku lub bazie danych. Jedną z odmian tego wzorca jest tzw. abstrakcyjna fabryka klas (ang. abstract class factory). Klasa ta potrafi sama odtwarzać klasy, przy czym na poziomie kodu źródłowego klasy nie są zawarte żadne informacje na temat tego, jakie klasy mogą być przez nią konstruowane. Innymi słowy w kodzie tym nie wymienia się jawnie konstruktorów określonych klas. Konieczne jest jednak wcześniejsze zarejestrowanie w klasie identyfikatora klasy, a w językach o silnych typach, takich jak c++ w swoim standardzie, konieczne jest skojarzenie z identyfikatorem klasy adresu funkcji, najczęściej statycznej, która zawiera wywołanie konstruktora określonej kasy i zwraca w wyniku adres będący wskazaniem na obiekt abstrakcyjnej klasy-korzenia (ang. root class). Warunkiem jest jednak to, aby klasa, którą chcemy odtworzyć była pochodną wspomnianej klasy-korzenia. W opracowanej w ramach prac nad artykułem bibliotece BMU zastosowano takie właśnie rozwiązanie. Jedynym problemem, jaki pozostaje do rozwiązania jest problem gromadzenia instancji odtwarzanych klas. Ponieważ jednak wszystkie odtwarzane obiekty mają wspólną klasę bazową, wystarczy w odpowiedniej strukturze zapisać referencje lub wskazania na utworzone obiekty.
Na rys. 1 przedstawiono analityczną strukturę klas zaimplementowanych w bibliotece BMU. Struktura ta jest oczywiście jedynie zarysem dalszego projektu i implementacji, pozwala jednak na zobrazowanie przebiegu procesu odtwarzania instancji klasy. Proces ten zobrazowano dokładniej na rys. 2. w postaci diagramu przebiegu. Warto w tym momencie zauważyć, że jedyna znaczeniowa zależność pomiędzy klasami bibliotek VCL i przedstawionych na diagramie klas biblioteki BMU dotyczy wyłącznie klasy TDataSet, co pozwala na całkowite uniezależnienie działania biblioteki od szczegółów implementacyjnych związanych z konkretnym standardem komunikowania się aplikacji z bazą danych.


Rysunek 1. Analityczna struktura klas biblioteki BMU.

                   

Rysunek 2. Diagram przebiegu interakcji związanej z odtwarzaniem i kasowaniem obiektu.


 

Projekt i implementacja

Zasadniczą część modelu projektowego (rys. 3) biblioteki BMU stanowi pięć klas. Trzy z nich odpowiadają dokładnie klasom modelu analitycznego, a więc klasom Root Class, Abstract Class Factory oraz klasie Container. Są to klasy abstrakcyjne, którymi są odpowiednio: TBMUBusiness Object, TBMUClassFactory i TBMUObjectHandler. Dwie pozostałe, tj. TBMUSingleObjectHandler i TBMUMultipleObjectHandler precyzują określony sposób odtwarzania schematu. Pierwsza klasa, którą nazwać można zarządcą pojedynczej instancji, odtwarza w pamięci operacyjnej tylko jedna instancję klasy, zawsze tą, która związana jest bieżącym rekordem zbioru danych. Rekord bieżący to ten, na którym ustawiony jest wskaźnik pozycji. Wartości pól tegoż rekordu zapisywane są już na poziomie biblioteki VCL w odpowiedniej strukturze (właściwość Fields) klasy TDataSet, co ułatwia znacznie ich odczytywanie i zapisywanie. Druga z wymienionych, tzn. TBMUMultipleObjectHandler, pozwala na zarządzanie wieloma instancjami. Dlatego też nazwano ją zarządcą wielu instancji. Klasa ta tworzy instancje dla wszystkich rekordów znajdujących się w zbiorze danych po uwzględnieniu ustawień filtrowania.

Rysunek 3. Diagram klas biblioteki BMU - model projektowy.

Istotną cecha zaprojektowanej biblioteki jest możliwość odtwarzania struktur obiektów na podstawie struktur powiązań pomiędzy zbiorami danych. Dotyczy to zbiorów reprezentujących powiązane ze sobą tabele bazy danych. Jeśli tak zadecyduje projektant aplikacji, zarządca instancji może sam podążać śladem powiązań typu Master-Detail pomiędzy zbiorami danych i odtwarzać kolejne elementy schematu zapisanego bazie danych (właściwości AutoFindDetails i BuildWithParts ustawione na wartość true). Możliwe jest także jawne wskazanie zbiorów, które chcemy w danym momencie odtworzyć w budowanym schemacie obiektowym podając nazwy zarządców dla tych zbiorów danych, które tworzą określoną strukturę (właściwość BoundHandlers). Dzięki temu mechanizmowi możliwe stało się odtwarzanie schematu obiektowego dla bardziej złożonych sytuacji, np. dla formularzy edycyjnych operujących na kilku tabelach bazy danych.
Jak już wspomniano podczas implementacji biblioteki posłużono się standardowymi mechanizmami rozszerzania środowisk IDE firmy Borland. Ich istota polega na umożliwieniu użytkownikowi środowiska, implementacji własnych wyspecjalizowanych komponentów. Implementacja własnych komponentów jest stosunkowo prosta i sprowadza się do utworzenia odrębnego projektu tzw. pakietu (ang. Package). Pakiet zawiera zazwyczaj kod źródłowy kilku komponentów składających się na określoną bibliotekę. Po wykonaniu kompilacji pakietu i jego zainstalowaniu, użytkownik środowiska może korzystać z nowych komponentów na takich samych zasadach, na jakich korzysta z komponentów dostarczonych wraz ze środowiskiem. Interfejs biblioteki BMU stanowią trzy komponenty, które reprezentują fabrykę klas oraz omówionych wcześniej zarządców instancji. Widok palety komponentów biblioteki BMU w obecnej wersji (wersja 2.0) przedstawiono na rys. 4.
 

Rysunek 4. Paleta komponentów biblioteki BMU.

Podsumowanie

Ponowne spotkanie się obu zasadniczych nurtów metodologicznych, jakie wyłoniły się na przestrzeni ostatnich kilku dekad rozwoju inżynierii oprogramowania, tzn. historycznie wcześniej rozpoczętego nurtu strukturalnego i późniejszego, obiektowego jest niewątpliwie zjawiskiem ciekawym. Nie spodziewali się tego z pewnością stojący w opozycji do zasad modelowania strukturalnego pomysłodawcy metod obiektowych. Zaistniała sytuacja ma jednak swoje głębokie przesłanki praktyczne. Wynika ona bowiem z faktu utrwalenia się tych elementów obu podejść, które zyskały, ze względu na swoją przydatność, szerokie praktyczne zastosowanie. W przypadku modelu strukturalnego utrwalił się przyjęty relacyjny model danych oraz oprogramowanie systemów zarządzania bazami danych, które realizuje jego postulaty. Sama metodyka projektowania, być może poza jej elementami odnoszącymi się do formułowania wymagań, nie przyjęła się. Została ona wyparta przez podejście obiektowe, szczególnie takie, w którym bazuje się na zastosowaniu notacji języka UML. Metodyka obiektowa pozwoliła na przeniesienie do struktur programów komputerowych elementów rzeczywistego świata i znacznie ułatwiła analitykom i projektantom dekompozycję bardziej złożonych zagadnień. Jej słabym elementem były jednak mechanizmy składowania danych, a w szczególności niemożność ugruntowania się i upowszechnienia określonych standardów dla tzw. obiektowych baz danych. Stąd wyniknęła konieczność ponownego odwołania się do mechanizmów składowania danych przyjętych w koncepcji strukturalnej.
Opracowane przez autorów artykułu rozwiązanie problemu integracji modelu obiektowego z środowiskiem programistycznym pracującym z bazami relacyjnymi jest z pewnością sporym uproszczeniem zarysowanego w artykule problemu. W porównaniu z innymi rozwiązaniami, szczególnie tworzonymi komercyjnie, jego funkcjonalność jest pewnością ograniczona. Jak jednak wynika z praktycznych testów, zastosowanie biblioteki BMU pozwala na tworzenie znacznie bardziej czytelnych i poprawnych metodycznie aplikacji obiektowych i ułatwia pracę projektanta. Ponadto zastosowanie biblioteki wymusza na projektancie wcześniejsze zrozumienie dziedziny problemowej programu, co wpływa bardzo pozytywnie na jakość powstającej aplikacji.
Nakreślając plan dalszych prac nad rozwiązaniem opisanym w artykule należy uwzględnić fakt, że firma Borland wprowadziła do najnowszej wersji swojego środowiska IDE, a mianowicie w ukazującym się na rynku w momencie powstawania tego artykułu Borland Developer Studio 2006, rozwiązanie Borland ECO będące komercyjnym rozwiązaniem dla problemu integracji obiektowo-relacyjnej. Należy jednak podkreślić, że pełna wersja platformy ECO dostępna jest jedynie w wersji Enterprise środowiska, która jest wersją najdroższą. Co z pewnością uniemożliwi jej wykorzystanie w mniejszych firmach oraz dla celów edukacyjnych. Tak więc prace nad zagadnieniem będą kontynuowane. Te najbliższe dotyczyć będą sprzężenia podążającego w odwrotnym kierunku, tzn. konstruowania schematu relacyjnego na podstawie struktur tworzonych przez obiekty.
 

© SYSINFO
Projekt: Madonet