UML Inzynieria oprogramowania Wydanie II 2

background image

Wydawnictwo Helion

ul. Koœciuszki 1c

44-100 Gliwice

tel. 032 230 98 63

e-mail: helion@helion.pl

UML. In¿ynieria

oprogramowania.

Wydanie II

Praktyczny podrêcznik do nauki jêzyka UML

• Jak zaprojektowaæ dobry system?

• Jak poprawnie tworzyæ i odczytywaæ modele?

• Jak w praktyce stosowaæ UML i poprawiæ jakoœæ projektowanych produktów?

W œwiecie informatyki dobry projekt to czêsto wiêcej ni¿ po³owa sukcesu, a wraz ze

wzrostem popularnoœci obiektowych jêzyków programowania UML — ujednolicony jêzyk

modelowania przeznaczony do reprezentacji elementów w analizie obiektowej i programowaniu

obiektowym — sta³ siê podstawowym narzêdziem do tworzenia modeli. Dlatego te¿

trudno wyobraziæ sobie dobrego informatyka, który nie potrafi przygotowaæ poprawnego

projektu w tym jêzyku lub odczytaæ modelu utworzonego przez kogoœ innego.
„UML. In¿ynieria oprogramowania. Wydanie II” to przystêpny podrêcznik dla studentów

i informatyków pragn¹cych nie tylko poznaæ ujednolicony jêzyk modelowania, ale przede

wszystkim nauczyæ siê korzystaæ z niego w kontekœcie in¿ynierii oprogramowania.

Czytaj¹c go, dowiesz siê, jak powinien wygl¹daæ dobry system, poznasz sk³adniê

i funkcje jêzyka UML, a przedstawione studia przypadku pozwol¹ Ci zobaczyæ, jak

u¿ywaæ go do projektowania praktycznych rozwi¹zañ.

• Projektowanie systemów bazuj¹cych na komponentach

• Wprowadzenie do obiektowoœci

• Efektywny proces projektowania

• Opracowywanie modeli klas

• Przygotowywanie modeli przypadków u¿ycia

• Tworzenie diagramów interakcji, stanów i aktywnoœci

• Przygotowywanie diagramów struktury i wdro¿eñ

• Stosowanie komponentów i wzorców

• Dbanie o jakoœæ procesu i produktu

• Praktyczne przyk³ady projektowania systemów

Jeœli chcesz tworzyæ oprogramowanie najwy¿szej jakoœci, zacznij od dobrego projektu

Autor: Perdita Stevens

T³umaczenie: Ireneusz Jakóbik

ISBN: 978-83-246-0805-8

Tytu³ orygina³u:

Using UML: Software Engineering

with Objects and Components (2nd Edition)

Format: B5, stron: 304

background image

X

Wstęp ...................................................................................................... 13

Część I Tło koncepcyjne .................................................................. 19

Rozdział I Inżynieria oprogramowania z użyciem komponentów ......................... 21

1.1. Co to jest dobry system? ......................................................................................... 21
1.2. Czy istnieją dobre systemy? ..................................................................................... 22

1.2.1. Problemy… ............................................................................................... 22
1.2.2. …a nawet katastrofalne niepowodzenia .................................................... 24
1.2.3. Obietnice, obietnice .................................................................................. 25

1.3. Jakie są dobre systemy? ............................................................................................ 26

1.3.1. Hermetyzacja: słabe powiązania ................................................................ 27
1.3.2. Abstrakcja: wysoki stopień spójności ......................................................... 30
1.3.3. Architektura i komponenty ........................................................................ 31
1.3.4. Projektowanie oparte na komponentach: modularność ............................ 33

1.4. Jak są zbudowane dobre systemy? ........................................................................... 33

Rozdział 2 Koncepcje obiektów ............................................................................... 35

2.1. Czym jest obiekt? ..................................................................................................... 35

2.1.1. Przykład ..................................................................................................... 37
2.1.2. Komunikaty ................................................................................................ 37
2.1.3. Interfejsy .................................................................................................... 38
2.1.4. Klasy .......................................................................................................... 39

2.2. Jaki to ma związek z celami poprzedniego rozdziału? .............................................. 42

2.2.1. Co wspólnego z komponentami mają obiekty? ......................................... 43

2.3. Dziedziczenie ........................................................................................................... 44
2.4. Polimorfizm i wiązanie dynamiczne ......................................................................... 46

Rozdział 3 Wstępne studium przypadku ................................................................. 49

3.1. Problem ................................................................................................................... 49

3.1.1. Sprecyzowanie wymagań ........................................................................... 49
3.1.2. Model przypadków użycia ......................................................................... 51

3.2. Zakres oraz iteracje ................................................................................................. 53
3.3. Identyfikowanie klas ................................................................................................. 55
3.4. Relacje między klasami ............................................................................................. 57
3.5. System w akcji ......................................................................................................... 60

3.5.1. Zmiany w systemie: diagramy stanów ....................................................... 64
3.5.2. Dalsze prace .............................................................................................. 64

background image

4

UML. Inżynieria oprogramowania

Rozdział 4 Proces projektowania ............................................................................. 67

4.1. Definicje terminów .................................................................................................. 67

4.1.1. Modele i języki modelowania .................................................................... 68
4.1.2. Proces i jakość ........................................................................................... 70

4.2. Proces projektowania .............................................................................................. 70

4.2.1. Zunifikowana metodologia? ....................................................................... 72
4.2.2. Procesy stosowane w UML ....................................................................... 73

4.3. System, projekt, model, diagram ............................................................................. 75

4.3.1. Wykorzystanie modeli ............................................................................... 76

Część II UML ..................................................................................... 79

Rozdział 5 Podstawy modeli klas ............................................................................. 81

5.1. Identyfikowanie obiektów i klas ............................................................................... 81

5.1.1. Co sprawia, że model klasy jest dobry? ..................................................... 81
5.1.2. Jak zbudować dobry model klasy ............................................................... 82
5.1.3. Jakim rodzajem rzeczy są klasy? ................................................................. 85
5.1.4. Obiekty ze świata rzeczywistego a ich reprezentacje w systemie ............ 85

5.2. Powiązania ............................................................................................................... 86

5.2.1. Wielokrotności .......................................................................................... 88

5.3. Atrybuty i operacje .................................................................................................. 89

5.3.1. Operacje .................................................................................................... 89
5.3.2. Atrybuty ..................................................................................................... 89

5.4. Generalizacja ............................................................................................................ 90

5.4.1. Korzystanie z języka polskiego w celu sprawdzenia, czy zachodzi

generalizacja ...................................................................................................... 93

5.4.2. Implementacja generalizacji: dziedziczenie ................................................ 93

5.5. Model klasy podczas opracowywania ...................................................................... 94
5.6. Karty CRC ............................................................................................................... 95

5.6.1. Tworzenie kart CRC ................................................................................. 95
5.6.2. Używanie kart CRC podczas opracowywania projektu ............................ 96
5.6.3. Przykład karty CRC ................................................................................... 97
5.6.4. Refaktoring ................................................................................................ 98

Rozdział 6 Więcej na temat modeli klas ................................................................ 101

6.1. Więcej na temat powiązań ..................................................................................... 101

6.1.1. Agregacja i kompozycja ........................................................................... 101
6.1.2. Role ......................................................................................................... 103
6.1.3. Możliwości nawigacji ............................................................................... 104
6.1.4. Powiązania kwalifikowane ....................................................................... 105
6.1.5. Powiązania pochodne .............................................................................. 107
6.1.6. Ograniczenia ............................................................................................ 108
6.1.7. Klasy powiązań ........................................................................................ 110

6.2. Więcej na temat klas .............................................................................................. 112

6.2.1. Interfejsy .................................................................................................. 113
6.2.2. Klasy abstrakcyjne .................................................................................... 115

6.3. Klasy sparametryzowane ....................................................................................... 117
6.4. Zależność ............................................................................................................... 118
6.5. Komponenty i pakiety ............................................................................................ 119
6.6. Widoczność i ochrona ........................................................................................... 119

background image

Spis treści

5

Rozdział 7 Najważniejsze informacje na temat modeli przypadków użycia ........ 121

7.1. Szczegóły dotyczące aktorów ................................................................................ 123
7.2. Przypadki użycia w szczegółach ............................................................................. 125
7.3. Granice systemu .................................................................................................... 126
7.4. Używanie przypadków użycia ............................................................................... 127

7.4.1. Przypadki użycia podczas gromadzenia wymagań ................................... 127
7.4.2. Przypadki użycia podczas projektowania ................................................ 128

7.5. Możliwe problemy z przypadkami użycia .............................................................. 130

Rozdział 8 Więcej informacji na temat modeli przypadków użycia ..................... 133

8.1. Relacje między przypadkami użycia ....................................................................... 133

8.1.1. Przypadki użycia do wielokrotnego użycia: <<include>> .................... 134
8.1.2. Komponenty i przypadki użycia ............................................................... 136
8.1.3. Rozdzielanie wariantów zachowania: <<extend>> ............................. 138

8.2. Generalizacje ......................................................................................................... 139
8.3. Aktorzy i klasy ........................................................................................................ 140

8.3.1. Notacja: aktorzy jako klasy ...................................................................... 141

Rozdział 9 Najważniejsze informacje na temat diagramów interakcji .................. 143

9.1. Współprace ............................................................................................................ 144
9.2. Diagramy komunikacji ........................................................................................... 145
9.3. Diagramy sekwencji ............................................................................................... 147
9.4. Więcej zaawansowanych funkcji ............................................................................ 150

9.4.1. Komunikaty z obiektu do samego siebie ................................................. 150
9.4.2. Zwracane wartości .................................................................................. 151
9.4.3. Tworzenie i usuwanie obiektów ............................................................. 152

9.5. Diagramy interakcji służące innym celom .............................................................. 154

9.5.1. Pokazywanie, jak klasa udostępnia operację ............................................ 154
9.5.2. Opisywanie, jak działa wzorzec projektowy ........................................... 154
9.5.3. Opisywanie, jak można użyć komponentu .............................................. 154

Rozdział 10 Więcej informacji na temat diagramów interakcji ............................... 155

10.1. Więcej niż tylko proste sekwencje komunikatów ................................................ 155

10.1.1. Zachowania warunkowe ....................................................................... 155
10.1.2. Iteracja ................................................................................................... 157

10.2. Współbieżność ..................................................................................................... 158

10.2.1. Modelowanie ścieżek kontroli ............................................................... 159

Rozdział 11 Najważniejsze informacje na temat diagramów stanów i aktywności ......165

11.1. Diagramy stanów ................................................................................................. 166

11.1.1. Niespodziewane komunikaty ................................................................ 167
11.1.2. Poziom abstrakcji ................................................................................... 168
11.1.3. Stany, zmiany stanu i zdarzenia .............................................................. 168
11.1.4. Akcje ...................................................................................................... 169
11.1.5. Dozór .................................................................................................... 171

11.2. Diagramy aktywności ........................................................................................... 174

Rozdział 12 Więcej informacji na temat diagramów stanów ................................... 179

12.1. Inne rodzaje zdarzeń ........................................................................................... 179
12.2. Inne rodzaje akcji ................................................................................................. 180
12.3. Zaglądanie do wnętrza stanów ............................................................................ 181
12.4. Współbieżność w obrębie stanów ....................................................................... 183

background image

6

UML. Inżynieria oprogramowania

Rozdział 13 Diagramy architektury i wdrożeń ....................................................... 185

13.1. Diagramy struktury komponentów ..................................................................... 185
13.2. Model wdrożeń ................................................................................................... 187

13.2.1. Warstwa fizyczna ................................................................................... 187
13.2.2. Wdrażanie oprogramowania na sprzęcie ............................................... 187

Rozdział 14 Pakiety i modele ................................................................................... 191

14.1. Pakiety ................................................................................................................. 191

14.1.1. Kontrolowanie przestrzeni nazw ........................................................... 192

14.2. Modele ................................................................................................................. 194

Część III Studia przypadków ........................................................... 197

Rozdział 15 Administrowanie I4 .............................................................................. 199

15.1. Studium przypadku .............................................................................................. 199

15.1.1. Model klas .............................................................................................. 203
15.1.2. Dynamika ............................................................................................... 204
15.1.3. Diagramy stanów ................................................................................... 204
15.1.4. Diagramy aktywności ............................................................................. 204

15.2. Dyskusja ............................................................................................................... 205

Rozdział 16 Gry planszowe ...................................................................................... 207

16.1. Zakres i wstępna analiza ...................................................................................... 208

16.1.1. „Kółko i krzyżyk” ................................................................................... 208
16.1.2. Szachy .................................................................................................... 209

16.2. Interakcja ............................................................................................................. 213
16.3. Z powrotem do szkieletu aplikacji ....................................................................... 215
16.4. Stany .................................................................................................................... 217

Rozdział 17 Symulacja metodą kolejnych zdarzeń ................................................. 219

17.1. Wymagania ........................................................................................................... 219

17.1.1. Bardziej szczegółowy opis ..................................................................... 220

17.2. Zarys modelu klasy .............................................................................................. 222
17.3. Przypadki użycia .................................................................................................. 224

17.3.1. Podsumowanie przypadku użycia tworzenie modelu ............................ 224
17.3.2. Podsumowanie przypadku użycia obserwowanie zachowania .............. 225
17.3.3. Podsumowanie przypadku użycia zbieranie danych statystycznych ...... 225
17.3.4. Podsumowanie przypadku użycia uruchomienie modelu ...................... 225

17.4. Standardowy mechanizm symulacji opartej na procesie ...................................... 226
17.5. Powiązania i możliwości nawigacji ....................................................................... 227
17.6. Klasy w szczegółach ............................................................................................. 230

17.6.1. Klasa Zarzadca ....................................................................................... 230
17.6.2. Klasa JednostkaAktywna ........................................................................ 231
17.6.3. Klasa JednostkaPasywna ........................................................................ 233
17.6.4. Klasa Zasob ............................................................................................ 233

17.7. Klasa Raport ......................................................................................................... 236
17.8. Klasa DaneStatystyczne ....................................................................................... 236

17.8.1. Klasa Srednia .......................................................................................... 236

17.9. Budowanie kompletnego modelu symulacji ......................................................... 237
17.10. Ucztujący filozofowie ......................................................................................... 238

background image

Spis treści

7

Część IV W stronę praktyki ............................................................. 241

Rozdział 18 Wielokrotne używanie: komponenty i wzorce .................................... 243

18.1. Praktyczne informacje na temat wielokrotnego używania ................................... 243

18.1.1. Co może być użyte wielokrotnie i w jaki sposób? ................................. 244
18.1.2. Dlaczego używać powtórnie? ................................................................ 246
18.1.3. Dlaczego używanie wielokrotne jest trudne? ........................................ 247
18.1.4. Które komponenty w naturalny sposób nadają się

do powtórnego użycia? ........................................................................ 248

18.1.5. A co z budowaniem własnych komponentów? ...................................... 249
18.1.6. Jaką różnicę sprawia zorientowanie obiektowe? ................................... 250

18.2. Wzorce projektowe ............................................................................................. 251

18.2.1. Przykład: Fasada .................................................................................... 254
18.2.2. Język UML i wzorce .............................................................................. 254

18.3. Szkielety ............................................................................................................... 256

Rozdział 19 Jakość produktu: weryfikowanie, walidacja i testowanie .................... 257

19.1. Omówienie jakości .............................................................................................. 257
19.2. W jaki sposób można osiągnąć wysoką jakość? .................................................... 258

19.2.1. Nastawienie na produkt ........................................................................ 258
19.2.2. Nastawienie na proces .......................................................................... 258
19.2.3. Dalsza lektura ........................................................................................ 259

19.3. Weryfikacja .......................................................................................................... 259
19.4. Walidacja .............................................................................................................. 260

19.4.1. Użyteczność .......................................................................................... 261

19.5. Testowanie .......................................................................................................... 262

19.5.1. Wybieranie i przeprowadzanie testów .................................................. 263
19.5.2. Dodatkowe problemy związane ze zorientowaniem obiektowym ....... 265
19.5.3. Dlaczego testowanie jest często przeprowadzane źle? ......................... 267

19.6. Przeglądy i inspekcje ............................................................................................ 268

19.6.1. Problemy związane z przeglądami FTR ................................................. 269

Rozdział 20 Jakość procesu: zarządzanie, zespoły i kontrola jakości ...................... 271

20.1. Zarządzanie ......................................................................................................... 271

20.1.1. Zarządzanie projektem .......................................................................... 272
20.1.2. Szacowanie projektu iteracyjnego ......................................................... 273
20.1.3. Zarządzanie projektowaniem opartym na komponentach .................... 274
20.1.4. Zarządzanie ludźmi ................................................................................ 275

20.2. Zespoły ................................................................................................................ 276
20.3. Przywództwo ...................................................................................................... 277

20.3.1. Zmiana procesu projektowania ............................................................. 278

20.4. Kontrola jakości ................................................................................................... 279

20.4.1. Kontrola jakości w procesach iteracyjnych ............................................ 281
20.4.2. Kompleksowe zarządzanie jakością ....................................................... 281

20.5. Dalsza lektura ...................................................................................................... 283

Skorowidz ............................................................................................ 289

background image

W tym rozdziale będziemy kontynuować udzielanie odpowiedzi na pytanie „jakie są dobre
systemy?”, opisując zorientowany obiektowo paradygmat, który zawdzięcza swoją popular-
ność częściowo temu, że wspiera on projektowanie dobrych systemów. Korzystanie jednak
ze zorientowania obiektowego nie jest ani niezbędne, ani wystarczające do budowania do-
brych systemów. Udzielimy odpowiedzi na następujące pytania:

· Czym jest obiekt?
· W jaki sposób porozumiewają się obiekty?
· Jak jest zdefiniowany interfejs obiektu?
· Co obiekty mają wspólnego z komponentami?

Pod koniec omówimy dziedziczenie, polimorfizm i wiązanie dynamiczne.

Treści zawarte w tym rozdziale odnoszą się do standardowych, nowoczesnych, opartych

na klasach, obiektowo zorientowanych języków, takich jak Java, C# i C++. Większość roz-
działu można odnieść też do języków Smalltalk, Eiffel, CLOS, Perl5 i innych obiektowo zo-
rientowanych języków, z którymi można się spotkać, jednak dokładne ich porównywanie
wykracza poza zakres tej książki.

W niniejszym rozdziale są zawarte pytania na temat sposobów, w jaki języki programo-

wania używane przez

Czytelnika udostępniają omawiane obiektowo zorientowane funkcje.

Jeśli Czytelnik zna już jakiś język programowania, powinien być w stanie udzielić odpowie-
dzi na te pytania. Jeśli nie, warto aby przeczytał ten rozdział do końca, poznał podstawy wy-
branego języka, a następnie powrócił do pytań w celu sprawdzenia swojej wiedzy na temat
sposobów realizowania przez język zorientowania obiektowego. W pytaniach język progra-
mowania używany przez Czytelnika będziemy w skrócie nazywać „Twoim językiem”.

2.1. Czym jest obiekt?

Pojęciowo obiekt jest elementem, z którym można wchodzić w interakcje: można wysyłać
do niego różne komunikaty, a on będzie reagował. Zachowania obiektu zależą od jego bie-
żącego stanu wewnętrznego, który może ulegać zmianie, na przykład na skutek reakcji na

background image

36

Część I ¨ Tło koncepcyjne

otrzymany komunikat. Ważne jest, z którym obiektem zachodzi interakcja, i dlatego odnie-
sienie do obiektu następuje za pośrednictwem jego nazwy. Obiekt ma zatem swoją tożsa-
mość, która odróżnia go od wszystkich innych obiektów. Obiekt jest więc elementem posia-
dającym swoje zachowanie, stan i tożsamość; w taki sposób charakteryzuje go Grady Booch
[7]. Rozważymy te aspekty bardziej szczegółowo.

Przedmiot

Pojęcie przedmiotu jest bardziej interesujące, niż może się to początkowo wydawać. Obiekt
nie jest tylko elementem systemu; reprezentuje on w systemie koncepcję przedmiotu. Obiekt
może być na przykład reprezentacją prawdziwego przedmiotu, takiego jak zegar, tablica
rozdzielcza albo klient. W rzeczywistości obiekty pojawiły się jawnie po raz pierwszy w ję-
zyku Simula, w którym reprezentowały obiekty z realnego świata — te, które były symulo-
wane. Oczywiście, aby systemy programistyczne ogólnego przeznaczenia mogły być two-
rzone w oparciu o obiekty, obiekty nie muszą reprezentować fizycznie istniejących rzeczy.
Do kwestii sposobu rozpoznawania obiektów powrócimy w rozdziale 5.

P: Które z elementów następującej listy mogą być obiektami: młotek, kula, proces chemiczny,
miłość, mgła, rzeka, złość, kot, szarość, szary kot?

Stan

Stan obiektu to wszystkie dane aktualnie w nim zapisane. Zwykle obiekt ma wiele nazwa-
nych atrybutów (zmiennych obiektu, danych składowych), z których każdy ma określoną
wartość. Niektóre z atrybutów mogą podlegać zmianom, to znaczy ich wartości mogą się zmie-
niać. Obiekt reprezentujący na przykład klienta może mieć atrybut o nazwie adres, którego
wartość ulegnie modyfikacji po przeprowadzce klienta. Inne atrybuty mogą być niezmienne,
czyli stałe. Obiekt reprezentujący klienta może mieć atrybut, którego wartością będzie numer
identyfikacyjny klienta, pozostający bez zmian przez cały czas trwania życia obiektu. W większo-
ści współczesnych obiektowo zorientowanych języków programowania zestaw atrybutów
przypisanych obiektowi nie może ulec zmianie podczas trwania życia tego obiektu, chociaż
wartości atrybutów mogą się zmieniać.

Zachowanie

Zachowanie oznacza sposób, w jaki obiekt działa i reaguje w sensie zmian swojego stanu
i przekazywania komunikatów. Obiekt rozumie niektóre komunikaty, co znaczy, że może je
odbierać i zgodnie z nimi postępować. Zestaw komunikatów rozumianych przez obiekt, po-
dobnie jak i zestaw atrybutów, jest zwykle stały. Sposób, w jaki obiekt reaguje na komunikat,
może zależeć od aktualnych wartości jego atrybutów. Dzięki temu, nawet jeśli świat zewnętrzny
nie ma zagwarantowanego bezpośredniego dostępu do atrybutów (a zazwyczaj właśnie tak
jest), może pośrednio wpływać na ich wartości. W taki sposób wartości atrybutów decydują
o stanie obiektu.

background image

Rozdział 2. ¨ Koncepcje obiektów

37

Tożsamość

To zagadnienie może być trochę trudne. Idea jest taka, że obiekty są definiowane nie tylko
przez bieżące wartości swoich atrybutów. Istnienie obiektu jest ciągłe. Wartości atrybutów
mogą na przykład ulec zmianie, zwykle w odpowiedzi na komunikat, ale to będzie ciągle ten
sam obiekt. Odniesienie do obiektu następuje zazwyczaj przez jego nazwę (wartość zmien-
nej w programie-kliencie, na przykład

Klient

), ale nazwa obiektu to nie to samo, co sam

obiekt, ponieważ obiektowi można nadać kilka różnych nazw (co może być zaskakujące dla
programistów funkcyjnych, a niektórzy z nich twierdzą, że zorientowanie obiektowe można
zrealizować w czysto funkcyjny sposób; jednak tego zagadnienia nie będziemy poruszać
w niniejszej książce).

2.1.1. Przykład

Rozważmy obiekt o nazwie

mojZegar

, który rozumie komunikaty

podajCzas

i

ustawCzasNa(07:43)

,

i w ogólności

ustawCzasNa(nowyCzas)

dla sensownych wartości parametru

nowyCzas

. Można to

zrealizować, tworząc interfejs, który ogłosi, że przyjmuje komunikaty w postaci

podajCzas

i

ustawCzasNa(nowyCzas: Czas)

, gdzie

Czas

jest typem

1

, którego elementy są sensownymi

wartościami wspomnianego parametru

nowyCzas

.

W jaki sposób zaimplementować taką funkcję? Świat zewnętrzny nie musi tego wiedzieć

(informacja powinna być ukryta), ale być może obiekt ma atrybut

Czas

, którego wartość

zwraca w odpowiedzi na komunikat

podajCzas

i który jest ustawiany na wartość

nowyCzas

po

otrzymaniu przez obiekt komunikatu

ustawCzasNa(nowyCzas)

. Jest też możliwe, że komuni-

kat jest przekazywany do innego obiektu, znanego obiektowi

mójZegar

, i że to właśnie ten

inny obiekt pracuje z komunikatami.

2.1.2. Komunikaty

Z poprzedniego przykładu można wysnuć kilka wniosków na temat komunikatów. W skład
komunikatu wchodzi słowo kluczowe nazywane selektorem. W przykładzie selektorami są

podajCzas

i

ustawCzasNa

. Komunikat może, ale nie musi, zawierać jeden lub więcej argu-

mentów, które są wartościami przekazywanymi obiektowi, podobnie jak są przekazywane
wartości w przypadku wywoływania funkcji. W powyższym przykładzie

07:43

jest argu-

mentem, stanowiącym część komunikatu

ustawCzasNa(07:43)

. Zazwyczaj dla danego selektora

istnieje pojedyncza „prawidłowa” liczba argumentów, które powinny znajdować się w ko-
munikacie rozpoczynającym się tym od tego selektora. Nie można oczekiwać, że obiekt

mojZegar

zrozumie komunikat

ustawCzasNa

bez żadnego argumentu lub w postaci

ustawCzasNa(4, 12:30)

i tak dalej. Akceptowalne wartości argumentów również są ustalane w interfejsie obiektu

2

.

1

Albo klasą; klasy omówimy w podrozdziale 2.1.4.

2

Podając klasę (patrz podrozdział 2.1.4) lub niekiedy tylko interfejs, do których powinien należeć obiekt
przekazywany jako argument, lub jego typ, jeśli należy do typu podstawowego, takiego jak

int

albo

bool

— szczegóły zależą od konkretnego języka.

background image

38

Część I ¨ Tło koncepcyjne

P: Jaka jest składnia przesyłania komunikatów w Twoim języku?

Warto zauważyć, że wartości, na przykład wartości atrybutów obiektu albo wartości ar-

gumentów przesyłane w komunikatach, nie muszą należeć do typu podstawowego (takiego
jak znaki, liczby całkowite i tak dalej. Rodzaje typów podstawowych zależą od konkretnego
języka). Mogą to być również obiekty.

P: Jakie są podstawowe typy w Twoim języku?

Jedną z czynności, którą może wykonać obiekt w odpowiedzi na komunikat, jest wysła-

nie komunikatu do innego obiektu. Jeśli tak ma się stać, to powinien on w jakiś sposób po-
znać nazwę tego obiektu. Prawdopodobnie wartością jednego z jego atrybutów mógłby być
na przykład obiekt, którego nazwa byłaby wykorzystywana podczas wysyłania komunikatu.

P: Niech

o

będzie obiektem. Do jakich innych obiektów może wysyłać komunikaty obiekt

o

, oprócz

obiektów, dla których może być wartością ich atrybutów?

Warto zwrócić uwagę na to, że podczas wysyłania komunikatu do obiektu nie wiadomo,

jaki kod zostanie w wyniku wykonany, gdyż informacja o tym jest hermetyzowana. Będzie to
istotne pod koniec niniejszego rozdziału, kiedy omówimy wiązanie dynamiczne.

2.1.3. Interfejsy

Publiczny interfejs definiuje komunikaty, które będą przyjmowanie przez obiekt niezależnie
od miejsca ich pochodzenia. Zazwyczaj interfejs zapisuje selektory tych komunikatów, łącznie
z niektórymi informacjami na temat wymaganych argumentów oraz wartości, która ewentu-
alnie mogłaby być zwrócona. Jak wspomnieliśmy w rozdziale 1., korzystne byłoby, gdyby
interfejs zawierał jakiś rodzaj specyfikacji dotyczącej skutków wysłania komunikatu do obiektu.
Informacje tego typu są jednak podawane jedynie w komentarzach i dokumentacji. W więk-
szości języków programowania atrybuty mogą być zawarte również w publicznym interfejsie
obiektu. Umieszczenie atrybutu

x

w interfejsie jest równoważne z zadeklarowaniem, że

fragment danych tego obiektu,

x

, może być widziany i zmieniany z zewnątrz.

Zagadnienie do przedyskutowania 9

Jeśli korzystasz z języka, który nie zezwala na umieszczanie atrybutów w interfejsie publicz-
nym, to w jaki sposób możesz osiągnąć taki sam efekt, używając komunikatów w celu uzyska-
nia dostępu do danych? Czy są jakieś zalety stosowania takiego rozwiązania nawet w językach,
które dopuszczają używanie atrybutów w interfejsie? A wady?

Często jest tak, że nie każdy element systemu powinien mieć możliwość wysyłania do

obiektu wszystkich komunikatów, które dany obiekt mógłby zrozumieć. Dlatego też obiekt
może zwykle zrozumieć pewne komunikaty, które nie są częścią jego publicznego interfejsu.
Jak już na przykład wyjaśniliśmy w rozdziale 1., struktura danych używana przez moduł po-
winna być hermetyzowana, co jest zgodne z założeniem, że interfejs publiczny obiektu nie
powinien zazwyczaj zawierać atrybutów.

Obiekt zawsze może wysłać sam do siebie komunikat, który będzie w stanie zrozumieć.

Wysyłanie komunikatów samemu sobie może wydawać się dziwne lub zbyt skomplikowane,

background image

Rozdział 2. ¨ Koncepcje obiektów

39

jednak powód takiego postępowanie wyjaśnimy w dalszej części niniejszego rozdziału przy
okazji omawiania wiązania dynamicznego.

Zazwyczaj obiekt ma przynajmniej dwa interfejsy: publiczny, z którego może korzystać

dowolny element systemu, oraz obszerniejszy interfejs prywatny, z którego może korzystać
zarówno sam obiekt, jak i inne uprzywilejowane elementy systemu. Czasami może być jesz-
cze przydatny interfejs pośredni, udostępniający więcej możliwości niż interfejs publiczny,
ale mniej niż interfejs prywatny. Czasami w danym kontekście jest potrzebna tylko część
publicznego interfejsu obiektu, co powoduje wzrost liczby obiektów, które potencjalnie mo-
głyby być używane zastępczo. Może być zatem przydatne zapisywanie naprawdę potrzeb-
nych funkcji w mniejszym interfejsie, zamiast umieszczania ich w całym interfejsie publicz-
nym obiektu. Z tego względu obiekt może mieć (lub realizować) więcej niż tylko jeden
interfejs. I odwrotnie — wiele różnych obiektów może realizować taki sam interfejs.

W tej książce określenie „interfejs” zawsze będzie oznaczać interfejs publiczny. Jeśli bę-

dzie inaczej, zostanie to wyraźnie określone.

2.1.4. Klasy

Do tej pory omawialiśmy obiekty, jak gdyby każdy z nich był osobno definiowany, każdy miał
swój własny interfejs i sposób sprawdzania, który inny obiekt może wysyłać do niego komu-
nikaty. Oczywiście taki sposób tworzenia typowego systemu nie jest rozsądny, ponieważ
obiekty mają ze sobą wiele wspólnego. Jeśli przedsiębiorstwo ma 10 000 klientów i potrzeb-
ne jest zbudowanie systemu z obiektami reprezentującymi każdą z tych osób, to wszystkie
obiekty reprezentujące klientów będą posiadały wiele wspólnych cech. Ich zachowania po-
winny być spójne, aby programiści i osoby opiekujące się systemem mogły je zrozumieć.
Potrzebna będzie klasa obiektów reprezentująca klientów. Klasa opisuje zestaw obiektów
pełniących w systemie takie same funkcje.

W opartych na klasach, zorientowanych obiektowo językach programowania każdy obiekt

należy do klasy, a klasa obiektu determinuje jego interfejs

3

. Obiekt

mojZegar

może należeć do

klasy

Zegar

, której interfejs publiczny określa, że każdy obiekt klasy

Zegar

będzie udostępniał

operację

ustawCzasNa(nowyCzas: Czas)

. Znaczy to, że będzie rozumiał komunikaty z selekto-

rem

ustawCzasNa

i pojedynczym argumentem, który jest obiektem klasy (typu)

Czas

.

W rzeczywistości nawet sposób, w jaki obiekt reaguje na komunikaty, jest zdeterminowany

przez jego klasę, łącznie z wartościami atrybutów obiektu. Metoda jest określonym frag-
mentem kodu, w którym są zaimplementowane operacje. W interfejsie obiektu widoczne
jest jedynie to, że obiekt wykonuje operację; metoda, w której jest zaimplementowana funk-
cja, jest ukryta.

Podobnie zestaw atrybutów posiadanych przez obiekt jest zdeterminowany przez klasę,

chociaż oczywiście wartości przyjmowane przez atrybuty obiektu nie są określone w klasie
i mogą ulegać zmianom. Być może na przykład obiekty należące do klasy

Zegar

mają pry-

watny atrybut o nazwie

czas

. Jeśli taki sam komunikat zostanie wysłany do dwóch obiektów

tej samej klasy, w obu przypadkach zostanie wykonana ta sama metoda, chociaż efekt jej
wykonania może być znacząco różny, gdy atrybuty obiektów będą mieć inne wartości.

3

W rzeczywistości obiekt może należeć do więcej niż jednej klasy, z których klasa najbardziej szczególna
decyduje o jego interfejsie.

background image

40

Część I ¨ Tło koncepcyjne

Podsumowując, obiekty tej samej klasy mają takie same interfejsy. Publiczne i prywatne

interfejsy klasy

Zegar

mogłyby być opisane następująco:

- czas : Czas
+ podajCzas() : Czas
+ ustawCzasNa (nowyCzas: Czas)

W skład interfejsu publicznego wchodzą wiersze oznaczone znakiem

+

, a w skład inter-

fejsu prywatnego także wiersz ze znakiem

.

P: W jaki sposób definiuje się klasę, taką jak

Zegar

w Twoim języku? Czy interfejs i implementacja

są definiowane oddzielnie? Jak jest nazywany interfejs publiczny, a jak prywatny (może właśnie: pu-
bliczny i prywatny)? Czy są może jeszcze jakieś inne możliwości? Co one oznaczają?

Proces tworzenia nowego obiektu należącego do klasy

Zegar

jest nazywany tworzeniem

egzemplarza klasy

Zegar

, a powstały w wyniku obiekt egzemplarzem klasy

Zegar

. To właśnie

dlatego zmienne, których wartości należą do obiektu i które mogą ulegać zmianie w czasie
życia obiektu, są nazywane zmiennymi egzemplarza. Utworzenie obiektu oznacza utworze-
nie nowego egzemplarza klasy posiadającego własny stan i tożsamość, które będą pozosta-
wać spójne w obrębie wszystkich obiektów klasy. Proces tworzenia zazwyczaj obejmuje także
nadanie wartości atrybutom. Wartości mogą zostać określone w zleceniu utworzenia lub na-
dane przez klasę obiektu jako domyślne wartości początkowe. W językach takich jak C++
i Java klasa odgrywa bezpośrednią rolę podczas tworzenia nowych obiektów — w rzeczy-
wistości wykonuje całą pracę, nie ograniczając się jedynie do roli szablonu. Dlatego klasa
może być często uważana za fabrykę obiektów.

P: W jaki sposób jest tworzony w Twoim języku nowy obiekt danej klasy?

W wielu językach klasy mogą zachowywać się, jak gdyby same były obiektami. Klasa

Klient

mogłaby mieć atrybut

liczbaEgzemplarzy

, który byłby liczbą całkowitą zwiększaną za

każdym razem, gdy tworzony jest nowy obiekt typu

Klient

. Takie rozwiązanie konsekwentnie

przyjęto w języku Smalltalk, a w językach C++ i Java można odnaleźć jego ślady. W Smalltalk
na przykład nowy obiekt typu

Klient

zostałby utworzony przez wysłanie komunikatu (przy-

kładowo

new

) do klasy

Klient

. Reakcją klasy byłoby utworzenie nowego obiektu i zwrócenie

go do metody wywołującej.

Zagadnienie do przedyskutowania 10

Zastanów się, co by było, gdyby konsekwentnie stosować takie rozwiązanie. Stwierdziliśmy
już, że każdy obiekt ma swoją klasę. Jeśli więc klasa

k

zostanie uznana za obiekt, to co będzie

klasą dla

k

? I co będzie klasą tej klasy?

P: Czy Twój język posiada takie funkcje? Jakie dokładnie?

Dygresja: po co istnieją klasy?

Dlaczego nie wystarczą obiekty, które posiadają wymagany stan, zachowanie i tożsamość?

Klasy w zorientowanych obiektowo językach programowania służą dwóm celom. Po pierw-

sze, są wygodnym sposobem na opisanie zbioru (klasy) obiektów posiadających takie same
właściwości. W językach zorientowanych obiektowo klasy są używane przede wszystkim dla

background image

Rozdział 2. ¨ Koncepcje obiektów

41

wygody. Nie ma na przykład potrzeby przechowywania kopii kodu opisującego zachowania
obiektu w każdym obiekcie, chociaż można wyobrażać sobie, że w każdym obiekcie znajduje
się jego kod. Zamiast tego programista może jednorazowo napisać definicję klasy, a kompi-
lator utworzy pojedynczą reprezentację klasy i pozwoli obiektom na uzyskiwanie dostępu do
reprezentacji klasy w celu pobierania potrzebnego kodu.

Należy pamiętać, że taka wygoda wcale nie jest czymś błahym. Zasadniczym celem jest

przecież uczynienie systemów łatwiejszymi do zrozumienia, aby ich projektowanie i pielę-
gnacja były jak najbardziej tanie, łatwe i niezawodne. Sprawienie, że podobne obiekty dzielą
ten sam projekt oraz implementację, jest ważnym krokiem w tym kierunku.

W taki sposób przejawia się zasada

4

, która jest tak ważna w inżynierii oprogramowania

— nie tylko w odniesieniu do kodu — że ją wykrzyczymy:

PISZ TYLKO RAZ!

Oznacza to, że jeśli dwie kopie jakiegoś produktu inżynierii oprogramowania, na przy-

kład fragment kodu, fragment diagramu czy fragment tekstu pochodzący z dokumentu, po-
winny być spójne, to nie powinny istnieć w dwóch egzemplarzach. Za każdym razem, gdy ta
sama informacja jest zapisywana w więcej niż jednym miejscu, nie tylko marnuje się wysiłek
na powtórne robienie tego samego, zamiast zrobienia czegoś nowego, ale też naraża się na
kłopoty związane z pielęgnacją, ponieważ dwie wersje nigdy nie będą zsynchronizowane
bez żadnych starań. Sztuka stosowania tej zasady polega na stwierdzeniu, czy dwie kopie infor-
macji są rzeczywiście takie same, czy też zdarzyło się, że potencjalnie różne informacje są
akurat w danym momencie identyczne. W tym drugim przypadku skopiowanie i wklejenie
odpowiedniego fragmentu jest jak najbardziej prawidłowe. W pierwszym przypadku niechęć
do powielania informacji w więcej niż jednym miejscu jest zaletą. Należy tak postąpić wy-
łącznie wtedy, gdy istnieją ku temu dobre powody.

Zagadnienie do przedyskutowania 11

Czy ta zasada oznacza, że powielanie danych w rozproszonych bazach danych jest złym pomy-
słem? Dlaczego?

Zauważmy, że istnieją inne sposoby na tworzenie wielu podobnych obiektów, pisząc ich

kod tylko raz. Można na przykład zdefiniować prototyp obiektu, a następnie definiować ko-
lejne obiekty jako będące „takie jak tamten, ale z następującymi różnicami”. W takim przy-
padku również wystarczyłoby przechowywanie tylko jednej kopii kodu. Mniej więcej w taki
sposób postępuje się, programując w eleganckim, opartym na prototypach, języku Self. Ję-
zyki programowania oparte na klasach zdominowały jednak obecnie zorientowanie obiekto-
we i zapewne tak już pozostanie.

Po drugie, w większości zorientowanych obiektowo językach programowania klasy są

używane w taki sam sposób, jak w wielu innych językach są wykorzystywane typy — w celu
określenia, jakie wartości są dopuszczalne w określonych kontekstach, umożliwiając tym
samym kompilatorowi (oraz, co jest równie ważne, osobie czytającej kod) zrozumienie in-
tencji programisty i sprawdzenie, czy pewne rodzaje błędów nie wystąpią w programie.

4

Na którą kładzie nacisk zwłaszcza Kent Beck.

background image

42

Część I ¨ Tło koncepcyjne

Wiele osób uważa, że klasy i typy oznaczają tę samą rzecz. Rzeczywiście, jest to wygod-

ne i często nie prowadzi do żadnych nieporozumień, niemniej taki sposób myślenia jest
błędny. Należy pamiętać, że klasa definiuje nie tylko to, jakie komunikaty zrozumie obiekt,
co tak naprawdę wystarcza, aby sprawdzać, czy jest on akceptowalny w danym kontekście.
Określa również czynności obiektu wykonywane w odpowiedzi na komunikaty.

2.2. Jaki to ma związek z celami poprzedniego rozdziału?

Szukamy modułów, najlepiej nadających się do wielokrotnego używania wymiennych mo-
dułów, które mogłyby być dobrymi komponentami. Gdzie można je znaleźć w systemie
obiektowo zorientowanym?

Poszczególne obiekty mogłyby być uważane za moduły, ale nie byłyby one dobre. W syste-

mie znajduje się bowiem zazwyczaj wiele różnych modułów, które są blisko spokrewnione
pojęciowo. Gdyby każdy obiekt był uważany za odrębny moduł, to albo istniałyby wprowa-
dzające w błąd nieścisłości między pojęciowo powiązanymi modułami, albo potrzeba za-
chowania spójności powodowałaby tworzenie silnych skojarzeń.

Klasy powinny być słabo skojarzonymi, wysoce spójnymi modułami. Można zatem mieć

nadzieję (być może na próżno, co przedyskutujemy w następnym podrozdziale), że będzie
realne uzyskanie korzyści przedstawionych w rozdziale 1., a mianowicie niskiego kosztu
i krótkiego czasu opracowywania, łatwości pielęgnacji i wysokiej niezawodności. Zalety te
nie są cechą charakterystyczną zorientowania obiektowego, chociaż jest ono obecnie najle-
piej poznaną ścieżką do nich prowadzącą.

Kolejna uznana zaleta zorientowania obiektowego należy do innej kategorii. Naturalne

jest postrzeganie otaczającego świata w kategoriach obiektów. Warto przypomnieć sobie, że
głównym wymogiem stawianym przed dobrym systemem jest spełnianie oczekiwań użyt-
kowników i że prawidłowe uchwycenie tych oczekiwań oraz śledzenie ich zmian należą do
najtrudniejszych zadań związanych z tworzeniem systemów. Ważne jest, aby model systemu
(model domeny problemu i zachodzących procesów) był zgodny z modelem użytkownika.
Wydaje się, że obiekty z domeny problemu rzadziej ulegają zmianom, a same zmiany są
mniej dramatyczne, niż jest to w przypadku działania systemu wymaganego przez użytkow-
nika. Jeśli zatem system jest zbudowany w oparciu o te obiekty, to zmiany w systemie praw-
dopodobnie będą mniej rewolucyjne, niż gdyby system powstał w oparciu o bardziej ulotne
aspekty funkcjonalne. Podsumowując, należy mieć nadzieję, że system będzie zgodny z mo-
delem świata użytkownika, dzięki czemu będzie możliwe:

· łatwiejsze i dokładniejsze uchwycenie wymagań;
· lepsze nadążanie za zmianami wymagań użytkownika;
· tworzenie systemów, które prowadzą interakcje w bardziej naturalny sposób. Łatwiejsze

jest zaimplementowanie na przykład interfejsu użytkownika, który pozwala użytkowni-
kowi na interakcję z plikiem, zegarem albo drukarką jako całością (co ma sens z punktu
widzenia użytkownika, ponieważ te przedmioty są podobne do obiektów z rzeczywistego
świata), jeśli są one spójnymi obiektami także z punktu widzenia systemu. Z tego powo-
du interfejsy użytkownika były jednymi z pierwszych głównych obszarów, w których zo-
rientowanie obiektowe stało się popularne.

background image

Rozdział 2. ¨ Koncepcje obiektów

43

Należy jednak zaznaczyć, że te argumenty nie są bezdyskusyjne. W niektórych przypad-
kach, takich jak na przykład systemy obsługi zamówień, podejście zorientowane obiektowo
wydaje się bardzo naturalne, w innych (na przykład kompilatory) taka argumentacja jest
mniej przekonująca.

W każdym jednak przypadku gdy zorientowanie obiektowe osiąga swój cel, zwykle nie

jest tak z powodu charakterystycznych cech zorientowania obiektowego. Jest tak, ponieważ:

· podstawami zorientowania obiektowego są modularność, hermetyzacja i abstrakcja,
· zorientowane obiektowo języki programowania sprawiają, że osiąganie celów staje się

względnie proste, ponieważ istnieje uzasadnione prawdopodobieństwo, że oczywisty sposób
zrobienia czegoś jest również dobrym sposobem na zrobienie tego.

Zorientowanie obiektowe jest religią: to ludzie zostają zorientowani w stronę obiektów.

Zagadnienie do przedyskutowania 12

Istnienie jakich konsekwencji, dobrych i złych, może sugerować stwierdzenie, że „zorientowanie
obiektowe jest religią”?

2.2.1. Co wspólnego z komponentami mają obiekty?

Euforia towarzysząca zorientowaniu obiektowemu mogłaby czasami sugerować, że każda
klasa jest automatycznie komponentem, nadającym się do wielokrotnego używania. Oczywi-
ście nie jest to prawdą. W rozdziale 1. omówiliśmy powody, dla których możliwość wielo-
krotnego używania komponentu nie jest po prostu faktem o komponencie jako takim, ale
zależy od kontekstu projektu i proponowanego sposobu jego powtórnego użycia. Innym ważnym
czynnikiem jest to, że struktura klasy może być zbyt szczegółowa, aby mogła być efektywnie
wielokrotnie wykorzystywana. Aby na przykład można było wielokrotnie korzystać z poje-
dynczej klasy w sposób praktyczny i łatwy, należałoby pisać programy w tym samym języku
i sięgać do zgodnej architektury. Nie zawsze jest to niewykonalne. Istnieją powszechnie używa-
ne biblioteki klas, które odniosły sukces, i ich biblioteki mogą być uważane za komponenty
do wielokrotnego używania. Często jednak określenie komponentu odnosi się do grupy po-
wiązanych klas. Im więcej wysiłku włoży się w dostosowanie komponentu do kontekstu, tym
więcej korzyści powinien przynieść dany komponent, jeśli ten wysiłek ma być opłacalny.

Celowo rozmyliśmy kwestię tego, czy komponenty są zbudowane z obiektów, czy z klas;

nie dokonaliśmy jeszcze wyraźnego rozróżnienia między typem a egzemplarzem. Powód jest
taki, że wziąwszy pod uwagę szeroką definicję komponentu, oba te przypadki mogą być
prawdziwe. Klasa albo zbiór klas może być komponentem na poziomie kodu źródłowego.
Kontekst, w którym jest używany komponent, korzysta z udogodnień danego języka w celu
tworzenia obiektów klasy. W innych przypadkach komponent może realizować dostęp do
określonego, gotowego obiektu jakiejś klasy, realizując również dostęp do funkcji związa-
nych z tworzeniem kolejnych obiektów tej klasy. Należy pamiętać, że sam komponent ma
dobrze zdefiniowany interfejs. Jeśli komponent składa się z obiektów i (lub) klas, to interfejs
komponentu zwykle nie pozwala na dostęp do wszystkiego, co znajduje się w interfejsach
obiektu i wewnątrz klas. Komponent sam stara się być hermetyzowaną abstrakcją i prawdo-
podobnie jest właściwe, że ukrywa część lub całość swojej wewnętrznej struktury — na
przykład czy i jak składa się z obiektów i klas.

background image

44

Część I ¨ Tło koncepcyjne

Zagadnienie do przedyskutowania 13
Skorzystaj z sieci Web i innych dostępnych zasobów w celu odszukania popularnych kompo-
nentów architektury, takich jak JavaBeans, CORBA albo .NET. Co to jest architektura? Jaką
wewnętrzną strukturę może mieć komponent i jak jest zdefiniowany interfejs komponentu?

2.3. Dziedziczenie

Do tej pory omówiliśmy jedynie pojęciowe podstawy tego, co czasami jest nazywane pro-
jektem opartym na obiektach. W tym podrozdziale weźmiemy pod uwagę dziedziczenie,
które będąc pojęciowym elementem leżącym u podstaw obiektowo zorientowanego pro-
jektu, jest niczym lukier dla pączka. Jak wskazuje metafora, pojęcie to jest uważane za atrak-
cyjne i ważne, ale tak naprawdę jest mniej treściwe niż to, co do tej pory opisaliśmy w książce.

W niniejszym podrozdziale rozpatrzymy dziedziczenie jako techniczną właściwość języ-

ków zorientowanych obiektowo, użyteczną (w ograniczonym zakresie) podczas niskopozio-
mowego wielokrotnego wykorzystywania. W rozdziale 5. omówimy korzystanie z dziedzi-
czenia w modelowaniu.

Poniższy przykład został zaczerpnięty ze studium przypadku z rozdziału 15. W rozważa-

nym systemie istnieje klasa, której obiekty reprezentują wykładowców, oraz klasa, której
obiekty reprezentują opiekunów studiów. Opiekun studiów jest kimś w rodzaju wykładowcy,
a dokładniej jest wykładowcą, który oprócz pełnienia zwykłych obowiązków jest odpowiedzialny
także za nadzorowanie postępów poszczególnych studentów. W systemie

OpiekunStudiow

powinien rozumieć takie same komunikaty jak

Wykladowca

i dodatkowo powinien być w sta-

nie odpowiedzieć na komunikat

podopieczni

, zwracając zbiór obiektów typu

Student

.

Załóżmy, że klasa

Wykladowca

została już zaimplementowana i teraz należy zaprojektować

klasę

OpiekunStudiow

. Załóżmy też (wyłącznie dla skonkretyzowania przykładu), że używany

jest język podobny do C++, w którym interfejs klasy i jego implementacja są przechowywane
w oddzielnych plikach. Co jest potrzebne do zaimplementowania nowej klasy tak szybko jak
to tylko możliwe? Można skopiować i wkleić kod definiujący interfejs klasy

Wykladowca

do

nowego pliku z interfejsem i dodać u dołu opis dodatkowego komunikatu. Podobnie można
skopiować do pliku z implementacją nowej klasy kod, w którym zaimplementowano reakcję
obiektów klasy

Wykladowca

na komunikat, a następnie dokonać niezbędnych zmian. Jak już

jednak wspomnieliśmy, wielokrotne używanie kodu przez jego kopiowanie ma wady. Naj-
ważniejsza z nich jest taka, że w przypadku konieczności dokonania zmian w zduplikowa-
nym kodzie (na przykład wykryto błąd w programie) należy wprowadzić zmiany w dwóch
miejscach zamiast w jednym. Jest to uciążliwe i prawdopodobnie doprowadzi do błędów.

Zamiast tego obiektowo zorientowane języki programowania dopuszczają utworzenie

nowej klasy

OpiekunStudiow

na podstawie istniejącej klasy

Wykladowca

. Wystarczy zadekla-

rować, że klasa

OpiekunStudiow

jest podklasą klasy

Wykladowca

, a następnie dopisać jedynie

to, co ma związek z dodatkowymi atrybutami lub operacjami klasy

OpiekunStudiow

5

.

Co więcej, ponieważ w zorientowaniu obiektowym wiedza na temat kodu, jaki zostanie

wykonany przez obiekt po tym, gdy otrzyma on komunikat, jest hermetyzowana, istnieje

5

W niektórych językach, a zwłaszcza w języku Eiffel, można w podklasach usuwać atrybuty i operacje
nadklas, jednak takie postępowanie nie jest zazwyczaj uważane za dobry zwyczaj.

background image

Rozdział 2. ¨ Koncepcje obiektów

45

możliwość, aby w klasie

OpiekunStudiow

zaimplementować w odpowiedzi na komunikat inne

zachowania niż te, które są zaimplementowane w klasie

Wykladowca

. Oznacza to, że w klasie

OpiekunStudiow

można przesłonić niektóre z metod klasy

Wykladowca

. Oprócz dziedziczenia

metod po klasie

Wykladowca

, klasa

OpiekunStudiow

może zawierać nową metodę implemen-

tującą taką samą operację, dla której klasa

Wykladowca

miała już metodę. Kiedy obiekt klasy

OpiekunStudiow

otrzyma komunikat z żądaniem wykonania operacji, wywołana metoda bę-

dzie wyspecjalizowaną wersją metody udostępnianej przez klasę

OpiekunStudiow

.

Podklasa jest rozszerzoną, wyspecjalizowaną wersją swojej nadklasy. Zawiera operacje oraz
atrybuty nadklasy i możliwie jeszcze inne, dodatkowe elementy.

P: W jaki sposób jest definiowana podklasa w Twoim języku? Czy klasa może być bezpośrednią
podklasą kilku klas (dziedziczenie wielokrotne), czy nie?

Terminologia

Mówi się, że:

· klasa

OpiekunStudiow

dziedziczy po klasie

Wykladowca

,

· klasa

OpiekunStudiow

jest podklasą (lub klasą pochodną) klasy

Wykladowca

,

· klasa

OpiekunStudiow

jest specjalizacją klasy

Wykladowca

,

· klasa

OpiekunStudiow

jest bardziej wyspecjalizowana niż klasa

Wykladowca

,

· klasa

Wykladowca

jest nadklasą (lub klasą bazową) klasy

OpiekunStudiow

,

· klasa

Wykladowca

jest generalizacją klasy

OpiekunStudiow

.

Wszystkie powyższe określenia mają niemal to samo znaczenie. Często pojęcia podklasy i nad-
klasy są używane przy opisie konkretnych relacji pomiędzy pojęciami reprezentowanymi
w klasach. Zazwyczaj zachodzi między nimi związek. Związki pojęciowe jednak niekoniecz-
nie muszą być widoczne w strukturze klasy. Przeciwnie, niektórzy programiści używają
dziedziczenia w strukturze klasy w przypadkach, w których nie ma pojęciowego związku
dziedziczenia pomiędzy klasami (nie zawsze można polecać takie rozwiązanie. Może być
ono wygodne w krótszym okresie czasu, jednak niemal zawsze spowoduje nieporozumienia
po upływie dłuższego czasu).

Czy można powiedzieć, że klasa

OpiekunStudiow

należy do klasy

Wykladowca

? Można, jeśli

myśli się o klasach jak o zbiorach obiektów. Gdy mówi się o obiektach klasy

Wykladowca

,

z pewnością chce się uwzględnić także obiekty klasy

OpiekunStudiow

— po prostu ciągłe pi-

sanie o „klasie

Wykladowca

i dowolnych podklasach” jest zbyt niewygodne. Co więcej, zasa-

da, że obiekt podklasy powinien być zastępowalny obiektem nadklasy, jest fundamentalna.
Za każdym razem więc, gdy będzie mowa o obiektach należących do klasy, będzie to ozna-
czać także obiekty należące do podklas. Z drugiej strony bardzo wygodna byłaby możliwość
mówienia o „klasie tego obiektu”, jak gdyby należał on wyłącznie do jednej klasy. Przez
określenie „klasa” obiektu będziemy więc rozumieć najbardziej wyspecjalizowaną klasę, do
której należy dany obiekt. Oznacza to, że twierdzenie, iż zachowanie obiektu jest określone
przez jego klasę, pozostaje prawdziwe.

background image

46

Część I ¨ Tło koncepcyjne

2.4. Polimorfizm i wiązanie dynamiczne

Te dwa określenia są często w środowisku zorientowanym obiektowo używane zamiennie.
W rzeczywistości oznaczają one całkiem różne koncepcje. Ogólnie w językach programowa-
nia jedno pojęcie może istnieć bez drugiego, chociaż w językach zorientowanych obiektowo
są one spokrewnione i mają związek z dziedziczeniem.

Przede wszystkim należy zauważyć, że sam fakt, iż jedną klasę można definiować na

podstawie innej klasy, korzystając ponownie z jej kodu, nie musi mieć żadnego wpływu na
to, w jaki sposób kod-klient będzie traktował obiekty tych klas. Możliwy byłby język, w którym
dziedziczenie byłoby tylko sposobem na wielokrotne wykorzystywanie kodu. Można by zdefi-
niować klasę

OpiekunStudiow

na podstawie klasy

Wykladowca

, lecz cały kod klienta (a także

kompilator) musiałby dokładnie znać klasę każdego obiektu, z którym by wchodził w inte-
rakcję. Technicznie rzecz biorąc oznacza to, że można by utworzyć język z takim rodzajem
dziedziczenia, w którym występowałyby wyłącznie typy monomorficzne. Języki zoriento-
wane obiektowo radzą sobie jednak lepiej.

Polimorfizm

Określenie to, wywodzące się z języka greckiego, oznacza mający wiele kształtów. W języ-
kach obiektowo zorientowanych odnosi się do sytuacji, w której obiekt może należeć do jednego
z kilku typów. W obiektowo zorientowanej sytuacji zmienna polimorficzna mogłaby odnosić
się (w różnych przypadkach) do obiektów kilku różnych klas. Funkcja polimorficzna może
pobierać argumenty różnych typów. Powiedzieliśmy już, że obiekt podklasy powinien być
stosowany w każdej sytuacji, w której mógłby zostać użyty obiekt nadklasy. Powinno to oznaczać
w szczególności, że obiekt podklasy powinien być akceptowany jako wartość zmiennej, jeśli
jest akceptowany jako obiekt klasy bazowej. Innymi słowy, w obiektowo zorientowanym ję-
zyku każda zmienna jest polimorficzna — przynajmniej w tym ograniczonym znaczeniu.
Podobnie, jeśli jakaś funkcja (na przykład metoda) może pobierać argument klasy B, powin-
na być w stanie pobrać argument dowolnej klasy C, która jest podklasą klasy B; tak więc
również każda funkcja jest polimorficzna w tym ograniczonym sensie. Funkcja, która na
przykład oczekuje jako argumentu obiektu

Wykladowca

, nie powinna zgłosić błędu, jeśli jako

argument otrzyma obiekt

OpiekunStudiow

.

Zagadnienie do przedyskutowania 14

Czy w Twoim języku (w C albo w typologicznie funkcjonalnym języku programowania) jest re-
alizowany polimorfizm? Czy na polimorfizm są nałożone większe, czy mniejsze ograniczenia niż
w polimorfizmie obiektowo zorientowanym, który został tu opisany? Czy jest on przydatny?
W jaki sposób?

Polimorfizm pozwala na znaczne ograniczenie duplikacji kodu. Swoje prawdziwe możli-

wości pokazuje jednak w powiązaniu z związaniem dynamicznym.

background image

Rozdział 2. ¨ Koncepcje obiektów

47

Wiązanie dynamiczne

Słowo „wiązanie” w określeniu wiązanie dynamiczne (albo też późne wiązanie — oba te
określenia są używane zamiennie) odnosi się do procesu identyfikowania kodu, który powi-
nien zostać wykonany na skutek otrzymanego komunikatu. Zrozumienie tego będzie łatwiej-
sze po rozważeniu kilku przykładów.

Załóżmy, że interfejs obiektu

Wykladowca

zawiera funkcję

mozeWykonac (obowiazek: Obowia-

zek)

, która jako argument pobiera obiekt reprezentujący obowiązek administracyjny, a w wyniku

zwraca wartość logiczną, której wartością jest

prawda

, jeśli wykładowca może wypełnić dany

obowiązek. Przyjmijmy też założenie (trochę nierealne), że

OpiekunStudiow

jest w stanie zrobić

wszystko, a tym samym że zawsze powinien zwracać wartość

prawda

. Znaczy to, że podklasa

OpiekunStudiow

przeimplementowała (przesłoniła) funkcję

mozeWykonac

, prawdopodobnie za-

stępując skomplikowany kod sprawdzający informacje na temat zainteresowań lub doświad-
czenia wykładowcy prostym kodem, który zawsze zwraca wartość

prawda

.

Załóżmy teraz, że

wykladowcy

są zmienną odnoszącą się do zbioru obiektów klasy

Wykladowca

.

W tym zbiorze mogą być oczywiście zawarte także obiekty typu

OpiekunStudiow

, ponieważ

jeśli do zmiennej

wykladowcy

można dodawać obiekty klasy

Wykladowca

, to można do niej do-

dawać również obiekty klasy

OpiekunStudiow

. Przypuśćmy, że klient-zadanie próbujące znaleźć

kogoś do zorganizowania seminarium wykonuje kod w rodzaju poniższego pseudokodu:

dla kazdy o w wykladowca
o.mozeWykonac(organizacjaSeminarium)

Warto zwrócić uwagę na zapis z kropką w wierszu z wysyłanym komunikatem, który jest
wspólny dla wielu języków programowania. Wyrażenie

o.mozeWykonac(organizacjaSeminarium)

oznacza wysłanie komunikatu

mozeWykonac(organizacjaSeminarium)

do obiektu

o

. Może ono

być również używane w celu reprezentowania wartości, którą obiekt

o

zwróci klientowi po

przetworzeniu komunikatu.

Przyglądając się kodowi można przypuszczać, że obiekt

o

należy do klasy

Wykladowca

. Warto

przypomnieć ideę, że w obiekcie hermetyzowane jest jego zachowanie, a klasy wprowadzo-
no jedynie z potrzeby zwięzłości zapisu. Jeśli obiekt

o

znajduje się wyłącznie w klasie

Wykla-

dowca

, to powinien zostać wykonany kod obiektu

Wykladowca

dla komunikatu

mozeWykonac

,

czyli jego zachowanie w reakcji na komunikat. Co powinno się stać, gdy pętla

dla

osiągnie

obiekt

o

, który w rzeczywistości należy do klasy

OpiekunStudiow

? Oczywiście w takim przy-

padku powinien wykonać się kod klasy

OpiekunStudiow

(gdyby obiekt

o

rzeczywiście zabierał

ze sobą swój kod, działoby się tak automatycznie; fakt, że tak nie jest, wynika po prostu
z optymalizacji). Znaczy to, że ten sam fragment składni powinien spowodować wykonanie
dwóch różnych fragmentów kodu w różnych sytuacjach. Wysyłany komunikat jest dyna-
micznie wiązany z odpowiednim kodem

6

.

Na koniec rozważmy inny bardzo prosty przykład wiązania dynamicznego, który ilu-

struje także przypadek wysyłania przez obiekt komunikatu do samego siebie.

6

W najprostszy sposób można to zrobić, sprawdzając typ obiektu podczas wykonywania się programu.
W nowoczesnych językach jednak większość pracy bierze na siebie kompilator, co pozwala na większą
wydajność.

background image

48

Część I ¨ Tło koncepcyjne

Przypuśćmy, że interfejs klasy

Wykladowca

zawiera komunikat

mozliwosci

; w odpowiedzi

na niego obiekt klasy

Wykladowca

powinien zwrócić zbiór czynności, które wykładowca może

wykonać. Być może kod klasy

Wykladowca

jest zaimplementowany w podobny sposób jak

w poniższym pseudokodzie (w którym instrukcja

sam.mozeWykonac(obowiazek)

oznacza wy-

nik zwracany po wysłaniu do tego obiektu komunikatu z selektorem

mozeWykonac

i argu-

mentem

obowiazek

):

coMogeWykonac := pustyZbior
dla kazdy obowiazek w listaWszystkichObowiazkow
jesli (sam.mozeWykonac(obowiazek)) wtedy dodaj obowiazek do coMogeWykonac
inaczej zrob nic
zwroc coMogeWykonac

Oczywiście tę operację można przesłonić w nowej klasie

OpiekunStudiow

, tylko po co tak

robić (wydajność raczej nie będzie ważna)? Załóżmy, że kod pozostanie na swoim miejscu,
dzięki czemu zostanie bez zmian odziedziczony przez obiekty klasy

OpiekunStudiow

. Przy-

pomnijmy jednak, że w klasie

OpiekunStudiow

została przesłonięta operacja

mozeWykonac

. Co

się stanie, gdy obiekt klasy

OpiekunStudiow

otrzyma komunikat

mozliwosci

? Zostanie wyko-

nany powyższy kod — w czym nie ma nic szczególnego — co spowoduje wysłanie komuni-
katu

mozeWykonac

do siebie samego. Jest to obiekt klasy

OpiekunStudiow

, tak więc po otrzy-

maniu komunikatu

mozeWykonac

zostanie wykonana wyspecjalizowana wersja kodu zdefiniowana

w klasie

OpiekunStudiow

.

W przypadku używania czystego języka obiektowo zorientowanego takie zachowanie szybko

powinno stać się drugą naturą. Ostrożność należy zachować w przypadku języka C++: takie
zachowanie wykazują tylko metody wirtualne. Niektóre osoby, łącznie ze mną

7

, są głęboko

przekonane, że zaczynając programowanie obiektowo zorientowane w języku C++ powin-
no się początkowo tworzyć wyłącznie metody wirtualne

8

, a dopiero potem nauczyć się two-

rzenia metod niewirtualnych.

PODSUMOWANIE

Ten rozdział był krótkim wprowadzeniem do zorientowania obiektowego. Opisaliśmy, czym
jest obiekt i jak między obiektami są przesyłane komunikaty. Pokazaliśmy, że obiekty w systemie
można z pożytkiem podzielić na klasy, zamiast rozpatrywać je indywidualnie, oraz rozpo-
częliśmy rozpatrywanie powiązań między obiektami i komponentami. Omówiliśmy, jak za
pomocą dziedziczenia klasa może zostać zdefiniowana z wykorzystaniem definicji innej kla-
sy. Na koniec przedstawiliśmy inną cechę dziedziczenia w językach zorientowanych obiek-
towo — możliwość udostępniania polimorfizmu i wiązania dynamicznego.

W następnym rozdziale dokonamy wprowadzenia do głównego tematu tej książki — Ujed-
noliconego Języka Modelowania, który może być używany do określania specyfikacji i pro-
jektowania systemów korzystających z przewagi, jaką zapewnia zorientowanie obiektowe.

7

Stevens.

8

Łącznie (zwłaszcza) z destruktorami, ale nigdy z konstruktorami. Dlaczego?


Wyszukiwarka

Podobne podstrony:
Inzynieria oprogramowania w ujeciu obiektowym UML wzorce projektowe i Java iowuje
Inżynieria oprogramowania II
Excel w obliczeniach naukowych i inzynierskich Wydanie II exwob2
2007 08 UML – modelowanie statycznych aspektów oprogramowania [Inzynieria Oprogramowania]
Inżynieria oprogramowania 2 (Poznajemy UML)
Inżynieria oprogramowania 1 (Wprowadzenie do UML)
INF II stopien-Inzynieria oprogramowania
2007 11 UML – modelowanie dynamicznych aspektów oprogramowania [Inzynieria Oprogramowania]
Projekt UML, Nauka, Studia, Ćwiczenia, Inżynieria oprogramowania
2007 06 UML – potrzeba standaryzacji notacji [Inzynieria Oprogramowania]

więcej podobnych podstron