1 Obiektowe Języki Programowania Patryk Jasik Katedra Fizyki Teoretycznej i Informatyki Kwantowej Wydział Fizyki Technicznej i Matematyki Stosowanej Politechnika Gdańska Pokój 415GB E-mail: [email protected]@mif.pg.gda.pl Strona domowa: http://aqualung.mif.pg.gda.plhttp://aqualung.mif.pg.gda.pl Konsultacje: wtorek 17:00 – 18:00
2 Warunki zaliczenia przedmiotu Pisemny sprawdzian wiedzy – 20 pkt Uzyskanie 50%+1 punktów spośród wszystkich możliwych do zdobycia Termin zerowy: 29.01.2014 Termin podstawowy: 05.02.2014 Termin poprawkowy: 19.02.2014
3 Warunki zaliczenia przedmiotu OcenaPunkty bdb20 - 18,5 db plus18 - 16,5 db16 - 14,5 dst plus14 - 12,5 dst12 - 10,5
4 Literatura I. Sommerville – „Inżynieria oprogramowania”, WNT, Warszawa 2003 B. Meyer – „Programowanie zorientowane obiektowo”, Helion 2005 B. Stroustrup – „Język C++”, WNT, Warszawa 2004 J. Grębosz – „Symfonia C++ Standard”, Oficyna Kallimach, Kraków 2005 J. Grębosz – „Pasja C++”, Oficyna Kallimach, Kraków 2003 S.B. Lippman, J. Lajoie – „Podstawy języka C++”, WNT, Warszawa 2003 L.C. Tondo, P.B. Leung – „Podstawy języka C++ - ćwiczenia i rozwiązania”, WNT, Warszawa 2001 B. Eckel – „Thinking in C++”, Helion, 2002 N. M. Josuttis – „C++. Projektowanie zorientowane obiektowo”, Helion Piotr Wróblewski – „Język C++ dla programistów”, Helion D.R. Stephens, C. Diggins, J. Turkanis, J. Cogswell, „C++. Receptury”, Helion, 2006 I. Horton, „Visual C++ 2005 od podstaw”, Helion 2007
5 Literatura B. Eckel – „Thinking in Java”, Helion 2006 L. Lemay, R. Cadenhead – „Java 2 – dla każdego”, Helion 2001 J. Knudsen, P. Niemeyer – „Java. Wprowadzenie”, Helion 2003 M. Lis – „Java – ćwiczenia praktyczne”, Helion 2002 B. Boone – „Java dla programistów C i C++”, WNT 1998 I.F. Darwin – „Java. Receptury”, Helion J. Hilyard, S. Teilhet, „C#. Receptury”, Helion 2006 M. Lis, „Ćwiczenia C#”, Helion 2006 S. Orłowski, „C#. Tworzenie aplikacji sieciowych”, Helion 2007 J. Liberty, „C#. Programowanie”, Helion 2005 J. Liberty, B. MacDonald, „C#. Wprowadzenie”, Helion 2005 K. Hoffman, „Microsoft Visual C# 2005. Księga eksperta ”, Helion 2007
6 Historia BCPL, Richards, 1967 – prototyp języka C Język B, Thompson, 1969 – prototyp języka C Simula 67, Dahl, 1970 – pojęcie klasy wraz z klasami pochodnymi i funkcjami wirtualnymi Algol 68, Woodward, 1974 – przeciążanie operatorów i możliwość umieszczania deklaracji wszędzie tam, gdzie są dozwolone instrukcje Język C, Kernighan, Ritchie, 1978 – prototyp języka C++ Język ANSI C, Kernighan, Ritchie, 1988 ADA, Ichbiah, 1979 – obsługa wyjątków CLU, Liskov, 1979 – obsługa wyjątków C z klasami, Stroustrup, 1980 – rozszerzenie języka C C++, Stroustrup, lipiec 1983 – pierwsze zastosowanie poza pracownią badawczą Standard ISO C++, Stroustrup, 1998, poprawki do standardu 2003, nowy standard 2009 Java, Gosling, 1994 C#, Hejlsberg, początek XXI wieku
7 Uwagi techniczne – kompilatory i środowiska C++ –kompilator GNU, g++ –Dev-C++ –Microsoft Visual Studio 2008, 2010, 2012 –Borland C++ Builder –NetBeans –Eclipse –KDevelop –Code::Blocks –MinGW Dveloper Studio
8 Pierwszy program #include int main() { printf ("Witajcie! To jest wyklad z obiektowych jezykow programowania."); }
9 Pierwszy program #include using namespace std; int main() { cout
10 Drugi program #include int main() { int x, y, liczba; printf(„Podaj pierwsza liczbe: \n"); scanf(„%i”, &x); printf(„Podaj druga liczbe: \n"); scanf(„%i”, &y); liczba = x+y; printf("To jest nasz wynik: x+y=%i\n", liczba); }
11 Drugi program #include using namespace std ; int main() { int stopy ; // to do przechowywania liczby stop float metry ; // do wpisania wyniku float przelicznik = 0.3 ; // przelicznik: stopy na metry cout > stopy ; // przyjecie danej z klawiatury metry = stopy * przelicznik; // wlasciwe przeliczenie cout
12 Połączenie czterech kluczowych elementów leży u podstaw techniki programowania obiektowego Metoda budowania systemów Wymagania dotyczące niezawodności Zasada epistemologiczna Technika klasyfikacji
13 Metoda budowania systemów Wielokrotne wykorzystanie części składowych, z których tworzone jest oprogramowanie Każdy program komputerowy wykonuje pewne czynności na obiektach różnych typów Aby program był elastyczny i łatwo przystosowywał się do różnych zastosowań, należy skupić jego strukturę wokół obiektów, a nie akcji, jakie ma wykonywać Opracowanie bardzo wszechstronnego i dającego duże możliwości mechanizmu klas W tworzeniu systemów zorientowanych obiektowo klasy pełnią rolę fundamentu zarówno modułowej struktury programu, jak i systemu typów.
14 Wymagania dotyczące niezawodności Stanowią wyraz radykalnego podejścia do tworzenia oprogramowania, które ma robić dokładnie to, czego się od niego wymaga Każdy system traktuje się jako zbiór komponentów, które współpracują ze sobą w taki sam sposób jak sprawnie działające przedsiębiorstwa Każdy z komponentów musi wypełniać zobowiązania jasno określone w kontrakcie i ma prawo czerpać z tego korzyści, które również zostały w nim omówione
15 Zasada epistemologiczna Epistemologia - teoria poznania, dział filozofii, zajmujący się relacjami między poznawaniem, poznaniem a rzeczywistością. Epistemologia rozważa naturę takich pojęć jak: prawda, przekonanie, sąd, spostrzeganie, wiedza czy uzasadnienie.
16 Zasada epistemologiczna W technice obiektowej obiekty opisywane są przez klasy Definicje klas mówią jedynie, co możemy robić z obiektami Klasy składają się z listy dozwolonych operacji (zwanych też możliwościami klasy) i z list formalnych właściwości tych operacji (tak zwanych kontraktów) Wszystko opisywane jest dokładnie przez teorię abstrakcyjnych typów danych W świecie modelowania systemów informatycznych zakłada się obecność pewnej „zewnętrznej rzeczywistości”, która istnieje znacznie dłużej, niż jakiekolwiek oprogramowanie odwołujące się do niej. Jest to pozbawione sensu dla programisty stosującego techniki obiektowe, ponieważ rzeczywistość nie istnieje w oderwaniu od tego, co chcemy z nią zrobić. Programista nie zastanawia się nad tym, czy rzeczywistość w ogóle istnieje, czy nie, ponieważ jedyne co wie, to z czego może skorzystać. Wszystkie posiadane przez niego informacje na temat danej rzeczy sprowadzają się do tego, w jaki sposób można ją wykorzystać.
17 Technika klasyfikacji Wywodzi się z obserwacji, iż w każdej usystematyzowanej pracy umysłowej, a w szczególności przy prowadzenie rozważań o charakterze naukowym, konieczne jest opracowanie taksonomii dla badanych dziedzin. Technika obiektowa opiera się w dużym stopniu na metodzie klasyfikacji zwanej dziedziczeniem
18 FAQ W jaki sposób dowiadujemy się o nowych klasach i je opisujemy? Jak tworzone przez nas programy powinny manipulować klasami i odpowiadającymi im obiektami (egzemplarzami tych klas)? Jakie relacje mogą zachodzić między klasami? W jaki sposób możemy wykorzystać fakt, że między wieloma klasami często występują podobieństwa? Odpowiedzi: polimorfizm i wiązanie dynamiczne, nowe podejście do typów i kontroli typów, generyczność (zarówno ograniczona, jak i nieograniczona), ukrywanie informacji, asercje, bezpieczna obsługa wyjątków i automatyczne zwalnianie pamięci.
19 Główne cele programowania zorientowanego obiektowo Poprawność – to zdolność programów komputerowych do wykonywania dokładnie tych zadań, które im powierzono i które zdefiniowano w ich specyfikacjach (sprzęt – system operacyjny – kompilator – biblioteki – aplikacja). Odporność – to zdolność systemów komputerowych do prawidłowego reagowania na niestandardowe sytuacje. Brak katastrofy – wyświetlenie stosownych komunikatów o błędzie lub wejście w „tryb łagodnego zejścia”. Rozszerzalność – to możliwość łatwego dostosowywania programu komputerowego do zmian w specyfikacji (prostota i decentralizacja). Przystosowanie do wielokrotnego użycia – to zdolność elementów składowych oprogramowania do pełnienia roli elementów konstrukcyjnych wielu różnych aplikacji.
20 Główne cele programowania zorientowanego obiektowo Zgodność – to łatwość, z jaką można ze sobą łączyć poszczególne składniki oprogramowania. Kluczem do zgodności jest homogeniczność projektu i wypracowanie jednego standardu przesyłania informacji wewnątrz aplikacji: –standaryzowane formaty plików, np. tak jak w systemie operacyjnym Unix, w którym każdy plik tekstowy jest po prostu sekwencją znaków, –standaryzowane struktury danych, np. tak jak w programach napisanych w języku Lisp, w których wszystkie dane i programy są reprezentowane przez drzewa binarne, nazywane listami, –standaryzowane interfejsy użytkownika, np. tak jak w różnych wersjach systemu Windows, OS/2 czy MacOS, w których wszystkie narzędzia komunikują się z użytkownikiem w taki sam sposób, oparty na wykorzystaniu standardowych komponentów, takich jak okna, ikony, menu itd. Wydajność – to zdolność programu do stawiania komputerowi jak najmniejszych wymagań sprzętowych, rozumianych między innymi jako czas procesora, przestrzeń zajmowana w pamięci wewnętrznej i zewnętrznej, szerokość pasma wykorzystywanego przy przesyłaniu danych.
21 Główne cele programowania zorientowanego obiektowo Przenośność – to łatwość, z jaką dane oprogramowanie daje się przenosić między różnymi środowiskami sprzętowymi i programowymi Łatwość obsługi – to łatwość, z jaką ludzie o różnym doświadczeniu i kwalifikacjach mogą nauczyć się korzystania z aplikacji i stosowania ich do rozwiązywania problemów. Termin ten obejmuje też łatwość instalacji i nadzorowania pracy systemu. Zasada projektowania interfejsu użytkownika: Nie udawaj, że znasz użytkownika. Nie znasz! Funkcjonalność – to zbiór możliwości oferowanych przez system. Adekwatność czasowa – to gotowość programu komputerowego do wypuszczenia na rynek wtedy, gdy użytkownicy go potrzebują lub jeszcze zanim pojawi się taka potrzeba.
22 Główne cele programowania zorientowanego obiektowo Weryfikowalność – to łatwość przygotowywania procedur pozwalających określić, czy produkt znajduje się na akceptowalnym poziomie. W szczególności chodzi tu o dane testowe i procedury pozwalające na wykrywanie niepowodzeń i odnajdywanie tych błędów popełnionych na etapie walidacji danych i w fazie operacyjnej, które są przyczyną niepowodzeń Integralność – to zdolność oprogramowania do chronienia swoich składników (programów, danych) przed nieautoryzowanym dostępem i modyfikacjami Naprawialność – to udostępnianie możliwości naprawiania defektów Ekonomiczność – to uzupełnienie adekwatności czasowej, czyli zdolność systemu do zmieszczenia się w założonym budżecie
23 Dokumentacja systemów Dokumentacja zewnętrzna – użytkownicy mogą zrozumieć możliwości systemu i wygodnie z nich korzystać (konsekwencja wymagania zdefiniowanego jako łatwość obsługi). Dokumentacja wewnętrzna – pozwala zrozumieć strukturę i implementację systemu programistom (konsekwencja wymagania zdefiniowanego jako rozszerzalność). Dokumentacja interfejsów poszczególnych modułów – programiści mogą zrozumieć działanie funkcji dostarczanych przez dany moduł bez potrzeby zagłębiania się w jego implementację (konsekwencja wymagania zdefiniowanego jako przystosowanie do wielokrotnego użycia). Wynika ona również z rozszerzalności, ponieważ dokumentacja interfejsów modułów pozwala określić, czy dana zmiana będzie miała wpływ na konkretny moduł.
24 Dokumentacja systemów Zamiast traktować dokumentację jako osobny produkt, należy pisać maksymalnie samodokumentujący się kod. Uwzględniając w programie podsystem pomocy ekranowej, a także trzymając się jasnych i spójnych konwencji przy tworzeniu interfejsu użytkownika, ułatwia się zadanie autorom podręczników użytkownika i innych materiałów dydaktycznych. Zaimplementowanie programu w dobrym języku programowania zlikwiduje w dużej mierze konieczność tworzenia wewnętrznej dokumentacji, jeśli tylko język ten będzie sprzyjał organizacji i przejrzystości kodu. Są to jedne z najważniejszych czynników wpływających na wygląd notacji obiektowej. Notacja obiektowa powinna obsługiwać ukrywanie informacji i inne techniki (takie jak asercje) pozwalające oddzielić interfejsy modułów od ich implementacji. Pozwoli to zastosować narzędzia, które automatycznie wygenerują dokumentację interfejsów modułów na podstawie ich kodów źródłowych.
25 Kartezjusz – Rozprawa o metodzie (1637) Drugim [prawem, jakie postanowiłem przestrzegać, było] – podzielić każde z rozpatrywanych zagadnień na tyle cząstek, na ile się da i ile będzie wymagać lepsze rozwiązanie. Trzecim – prowadzić myśli po porządku, zaczynając od przedmiotów najprostszych i najłatwiejszych do poznania, aby następnie wznosić się pomału jak gdyby po stopniach, aż do poznania bardziej złożonych; należy się przy tym domniemywać prawidłowych związków nawet między tymi, które nie tworzą naturalnego szeregu.
26 Pięć kryteriów modułowości Dekompozycyjność – pomaga w rozkładaniu danego problemu programistycznego na pewną (niedużą) liczbę mniej złożonych problemów cząstkowych, tworzących wspólnie prostą strukturę, ale na tyle niezależnych, aby pracę nad każdym z nich można było prowadzić niezależnie od pozostałych. Liczbę zależności między systemami cząstkowymi należy sprowadzić do minimum. Kompozycyjność – zachęca do tworzenia składników oprogramowania, które można potem swobodnie ze sobą łączyć i w ten sposób tworzyć nowe programy, czasem nawet w innym środowisku niż to, w którym zostały one opracowane.
27 Pięć kryteriów modułowości Zrozumiałość – pomaga w pisaniu programów, których każdy moduł jest zrozumiały dla czytelnika nieznającego pozostałych modułów. Ciągłość – sprzyja tworzeniu aplikacji o takiej architekturze, że drobna zmiana specyfikacji problemu powoduje konieczność zmodyfikowania tylko jednego lub kilku modułów. Ochrona – prowadzi do tworzenia architektur, w których skutki wystąpienia w czasie wykonywania programu nienormalnej sytuacji w którymś z modułów są odczuwalne jedynie w tym module, a w najgorszym wypadku dają się we znaki kilku sąsiednim modułom.
28 Pięć reguł modułowości Mapowanie bezpośrednie – struktura modułowa opracowana w procesie tworzenia programu komputerowego powinna pozostawać zgodna z każdą strukturą modułową opracowaną w procesie modelowania problemu z danej dziedziny. Niewiele interfejsów – każdy moduł powinien komunikować się z tak małą liczbą innych modułów, jak to tylko możliwe. Nieduże interfejsy (słabe sprzężenia) – jeżeli dwa moduły komunikują się ze sobą, powinny wymieniać tylko tyle informacji, ile jest absolutnie niezbędne.
29 Pięć reguł modułowości Jawne interfejsy – zawsze wtedy, gdy moduły A i B komunikują się ze sobą, musi to być wyraźne uwidocznione w kodzie źródłowym A lub B, lub obu. Ukrywanie (hermetyzacja) informacji – projektant każdego modułu musi wybrać pewien podzbiór jego właściwości, który będzie stanowił oficjalną informację o tym module, udostępnianą twórcom modułów klienckich. Właściwości publiczne to właściwości eksportowane – interfejs modułu. Właściwości ukryte to właściwości prywatne.
30 Pięć zasad modułowości Zasada modułowych jednostek językowych – moduły muszą odpowiadać jednostkom składniowym występującym w stosowanym języku. Zasada samodokumentowania się kodu – projektant modułu powinien dążyć do tego, aby wszystkie informacje o module były zawarte w nim samym. Zasada jednolitego dostępu – wszystkie usługi oferowane przez moduł powinny być dostępne za pośrednictwem jednolitej notacji, która nie zdradza, czy zostały one zaimplementowane z wykorzystaniem danych przechowywanych statycznie, czy też obliczanych na bieżąco w razie potrzeby.
31 Pięć zasad modułowości Zasada otwarty-zamknięty – moduły powinny być jednocześnie otwarte i zamknięte. –Mówimy, że moduł jest otwarty, jeżeli można go rozszerzać. Na przykład powinna istnieć możliwość rozszerzania jego zbioru operacji lub dodania nowych pól do jego struktury. –Mówimy, że moduł jest zamknięty, jeżeli może być wykorzystywany przez inne moduły. Zakładamy tu więc, że ma on dobrze zdefiniowany, stabilny opis (interfejs zgodny z regułą ukrywania informacji). Zasada pojedynczego wyboru – zawsze wtedy, gdy program komputerowy musi obsługiwać jakiś zbiór alternatyw, ich pełna lista powinna być znana jednemu i tylko jednemu modułowi.
32 Cele wielokrotnego wykorzystania kodu Adekwatność czasowa – gdy korzystamy z gotowych komponentów, mamy mniej kodu do napisania, a tym samym możemy zrobić to szybciej Obniżenie kosztów konserwacji – gdy za oprogramowanie odpowiedzialny jest ktoś inny, również na niego spada obowiązek tworzenia nowych wersji. Pozwala to uniknąć paradoksu kompetentnego programisty – im więcej pracujesz, tym więcej masz do zrobienia, ponieważ użytkownicy twoich programów zaczynają prosić o rozszerzenie funkcjonalności, przeniesienie programu na inną platformę itd. Niezawodność – polegając na komponentach pochodzących z wiarygodnych źródeł mamy gwarancję, że autorzy tych komponentów podeszli do ich tworzenia w pełni profesjonalnie i poświęcili odpowiednią ilość czasu na ich dokładne przetestowanie.
33 Wydajność – twórcy komponentów stosują (a przynajmniej powinni) najlepsze znane algorytmy i struktury danych, ponieważ są to specjaliści z danej dziedziny. Natomiast w dużych projektach programistycznych trudno oczekiwać, aby w zespole byli sami eksperci, znający się na wszystkich zagadnieniach, o które otrze się tworzenie programu. Spójność – nie ma dobrej biblioteki, która nie zmuszałaby do stosowania przejrzystego, spójnego stylu projektowania aplikacji. Szczególnie styl niektórych najlepszych bibliotek obiektowych jest tak wyrazisty, że na zasadzie naturalnego procesu osmozy zaczyna wpływać na styl tworzenia aplikacji. Jest to bardzo istotny czynnik wyraźnie podnoszący jakość aplikacji tworzonych przez wieloosobowe grupy programistów. Inwestycja na przyszłość – tworzenie oprogramowania przystosowanego do wielokrotnego użycia jest sposobem na uwiecznienie doświadczenia i innowacyjnych pomysłów najlepszych programistów. Pozwala przekształcić delikatny i ulotny zasób w coś trwałego. Cele wielokrotnego wykorzystania kodu
34 Jakie elementy systemów nadają się do wielokrotnego wykorzystania? Personel Specyfikacje Projekty Wzorce projektowe Kody źródłowe Specjalistyczne komponenty Abstrakcyjne moduły
35 Problemy nietechniczne związane z wielokrotnym wykorzystaniem oprogramowania Syndrom NJTW (Nie Ja To Wymyśliłem) Syndrom NUN (Nawyk Unikania Nowatorstwa) Ekonomika przetargów Firmy programistyczne i ich strategie Dostęp do komponentów (indexing) Formaty dystrybucji komponentów wielokrotnego użytku
36 Wzorzec modułu has (t: TABLE, x: ELEMENT): BOOLEAN is -- Czy w t występuje x? local pos: POSITION do from pos := INITIAL_POSITION (x, t) until EXHAUSTED (pos, t) or else FOUND (pos, x, t) loop pos := NEXT (pos, x, t) end Result := not EXHAUSTED (pos, t) end
37 Kryteria obiektowości - kategorie Technika i język – są ściśle związane z procesem myślowym obecnym na etapie analizowania i projektowania oprogramowania oraz z notacją, którą się przy tym stosuje. Należy zwrócić uwagę na to, że (zwłaszcza w technice obiektowej) określenie „język” nie odnosi się jedynie do języka programowania w ścisłym tego słowa znaczeniu, ale też do notacji, mającej postać graficzną lub tekstową, którą stosuje się przy analizie i projektowaniu. Implementacja i środowiska – opisywane są podstawowe właściwości narzędzi, za pomocą których programiści wprowadzają w życie idee obiektowe. Biblioteki – technika obiektowa opiera się na wielokrotnym wykorzystywaniu gotowych komponentów programistycznych. Kryteria należące do tej kategorii odnoszą się zarówno do dostępności podstawowych bibliotek, jak i do mechanizmów niezbędnych do korzystania z nich i tworzenia nowych.
38 Kryteria obiektowości – Technika i język Jednolitość – zorientowany obiektowo język programowania, środowisko i wspierająca je technika, powinny mieć zastosowanie do całego cyklu życia aplikacji i to w sposób, który maksymalnie ułatwia przechodzenie między poszczególnymi czynnościami. Klasy – zarówno technika, jak i język powinny być zbudowane wokół pojęcia klasy. Asercje – język powinien dawać możliwość dołączania asercji (warunków początkowych, warunków końcowych i niezmienników) do klas i ich cech, musi opierać się na narzędziach służących do generowania dokumentacji na podstawie tych asercji i (opcjonalnie) pozwalać na monitorowanie asercji w trakcie wykonywania programów.
39 Kryteria obiektowości – Technika i język Klasy jako moduły – klasy powinny być jedynymi modułami, ponieważ obiektowość jest przede wszystkim techniką architektoniczną. Klasy jako typy – każdy typ powinien być oparty na jakiejś klasie. Klasy są same w sobie wystarczająco potężne, aby nie trzeba było już wprowadzać żadnego innego mechanizmu opisywania typów (INTEGER, REAL – klasy wbudowane). Sterowanie oparte na cechach – wywołania cech powinny być podstawowym mechanizmem sterującym. Wywołanie cech znane jest także jako przekazywanie komunikatów. Ukrywanie informacji – autor klasy powinien mieć możliwość zaznaczenia, czy dana cecha ma być dostępna dla wszystkich klientów, tylko dla wybranych, czy dla żadnego. Dobry, obiektowy język programowania nie powinien udostępniać żadnej postaci zmiennych globalnych.
40 Kryteria obiektowości – Technika i język Obsługa wyjątków – język powinien udostępniać mechanizm pozwalający na wychodzenie z niestandardowych sytuacji. Statyczna kontrola typów – dobrze zdefiniowany system kontroli typów powinien (przez narzucenie określonego zestawu reguł odnoszących się do deklarowania typów i gwarantujących zachowanie miedzy nimi zgodności) gwarantować bezpieczną obsługę typów w trakcie wykonywania programów, które zaakceptował. Reguły narzucające zgodność: –Każda encja (a więc każda nazwa odnosząca się w kodzie źródłowym do obiektów istniejących w czasie wykonywania programu) musi mieć jawnie określony typ, wywodzący się z jakiejś klasy; –Przy każdym wywołaniu na danej jednostce jakiejś cechy, uruchamiana jest cecha z klasy odpowiadającej tej encji (a cecha ta, z punktu widzenia ukrywania informacji, jest dostępna dla klasy obiektu wywołującego); –Przypisywanie i przetwarzanie argumentów musi podlegać regułom zgodności, opartym na dziedziczeniu, które wymagają, aby typ obiektu źródłowego był zgodny z typem obiektu docelowego.
41 Kryteria obiektowości – Technika i język Generyczność – powinno być możliwe pisanie klas z wykorzystaniem formalnych parametrów generycznych, reprezentujących dowolne typy. Ta postać parametryzowalności typów nazywana jest nieograniczoną generycznością. Jej uzupełnienie stanowi generyczność ograniczona, która jest związana z zagadnieniem dziedziczenia. Dziedziczenie pojedyncze – powinna istnieć możliwość zadeklarowania klasy jako potomka innej klasy. Dziedziczenie wielokrotne – każda klasa powinna mieć możliwość dziedziczenia z tylu innych klas, z ilu potrzeba. Powinien też istnieć mechanizm pozwalający radzić sobie z konfliktami nazw.
42 Kryteria obiektowości – Technika i język Dziedziczenie powtórne – powinien istnieć zbiór precyzyjnych reguł dotyczących cech nabywanych w wyniku wielokrotnego dziedziczenia, pozwalający programistom na ustalenie dla każdej powtórnie odziedziczonej cechy z osobna, czy ma być współużytkowana, czy replikowana. Ograniczona generyczność – mechanizm generyczności powinien obsługiwać jej ograniczoną postać. Połączenie generyczności i dziedziczenia pozwala zdefiniować klasę z generycznym parametrem, który nie reprezentuje dowolnego typu, lecz typ będący potomkiem danej klasy. Ponowna definicja – powinna istnieć możliwość ponownego zdefiniowania specyfikacji, sygnatury i implementacji dziedziczonej cechy. Polimorfizm – w trakcie działania programu powinna istnieć możliwość przypisywania encji (nazw w kodzie źródłowym, reprezentujących obiekty wykonywanego kodu) do obiektów różnych typów, aczkolwiek pozostająca pod nadzorem systemu kontroli typów uwzględniającego dziedzicznie.
43 Kryteria obiektowości – Technika i język Wiązanie dynamiczne – wywołanie cechy na jakiejś encji powinno zawsze powodować wywołanie tej jej wersji, jaka jest odpowiednia dla typu obiektu, który został dołączony do danej encji (a ten w czasie wykonywania programu może się zmieniać). Kontrola typów w trakcie wykonywania programu – w trakcie wykonywania programu powinna istnieć możliwość sprawdzenia, czy typ danego obiektu jest zgodny ze wskazanym typem. Klasy i cechy abstrakcyjne – powinna istnieć możliwość zadeklarowania klasy lub cechy jako abstrakcyjnej, czyli takiej, która jeszcze nie jest w pełni zaimplementowana. Zarządzanie pamięcią i mechanizm odzyskiwania pamięci – język powinien umożliwiać przeprowadzanie bezpiecznego, automatycznego zarządzania pamięcią, a implementacja powinna udostępniać automatyczny mechanizm przywracania pamięci.
44 Kryteria obiektowości – Implementacja i środowisko Automatyczne uaktualnianie – uaktualnianie programu po wprowadzeniu do niego zmian powinno odbywać się automatycznie. Analizowaniem zależności między klasami powinny zajmować się programy narzędziowe, a nie programiści. Szybkie uaktualnianie – czas potrzebny na przetworzenie zmian w programie i umożliwienie uruchomienia uaktualnionej wersji powinien zależeć jedynie od wielkości zmienianych komponentów, a nie od całkowitych rozmiarów aplikacji.
45 Kryteria obiektowości – Implementacja i środowisko Trwałość – powinien być dostępny mechanizm trwałego składowania obiektów, obsługujący pełną trwałość i umożliwiający przechowywanie na urządzeniach zewnętrznych wskazanych obiektów i wszystkich obiektów od nich zależnych. Obiekty te muszą dawać się wczytać zarówno w czasie tej samej sesji, jak i w kolejnych. Dokumentacja – powinny istnieć narzędzia pozwalające na automatyczne generowanie dokumentacji programów i klas. Przeglądanie – programy narzędziowe umożliwiające interaktywne przeglądanie klas powinny pozwalać programistom na szybkie i wygodne śledzenie zależności między klasami i cechami.
46 Kryteria obiektowości – Biblioteki Biblioteki podstawowe – powinien być dostępny zbiór klas przystosowanych do wielokrotnego użycia, implementujących najczęściej wykorzystywane struktury danych i algorytmy. Grafika i interfejs użytkownika – powinny istnieć klasy przystosowane do wielokrotnego użycia, umożliwiające tworzenie aplikacji o przyjemnym, graficznym interfejsie użytkownika. Mechanizmy rozwijania bibliotek – powinny istnieć mechanizmy pozwalające bibliotekom na ewoluowanie w sposób możliwie najmniej odbijający się na programach, które z nich korzystają. Mechanizmy katalogowania bibliotek – klasy biblioteczne powinny być zaopatrzone w informacje katalogowe umożliwiające wyszukiwanie ich po właściwościach.
47 Wzorzec modułu has (t: TABLE, x: ELEMENT): BOOLEAN is -- Czy w t występuje x? local pos: POSITION do from pos := INITIAL_POSITION (x, t) until EXHAUSTED (pos, t) or else FOUND (pos, x, t) loop pos := NEXT (pos, x, t) end Result := not EXHAUSTED (pos, t) end
48 Pięć wymagań dotyczących struktury modułu Zróżnicowanie typów – wzorzec podprogramu has zakłada istnienie tabeli zawierającej obiekty typu ELEMENT. Po przekształceniu wzorca w podprogram można doprecyzować, że typem tym ma być na przykład INTEGER lub BANK_ACCOUNT. To nie tak! Moduł przeszukiwawczy powinien sam z siebie obsługiwać elementy różnych typów. Za pomocą wzorca musimy tworzyć moduły o parametryzowalnych typach, moduły generyczne. Generyczność to mechanizm pozwalający na definiowanie parametryzowalnych wzorców modułów, których parametry reprezentują typy.
49 Pięć wymagań dotyczących struktury modułu Grupowanie podprogramów – sposób przeszukiwania tabeli zależy od tego, w jaki sposób została ona utworzona, jak wstawiane są do niej nowe elementy, jak są usuwane itd. Podprogram przeszukujący tabelę sam w sobie nie nadaje się jeszcze na zasób przystosowany do wielokrotnego użycia. Samowystarczalny moduł tego typu powinien mieć cały zestaw podprogramów realizujących powyższe operacje.
50 Pięć wymagań dotyczących struktury modułu Zróżnicowanie implementacji – wzorzec has jest bardzo ogólny. Pozwala on na stosowanie wielu różnych algorytmów i struktur danych. Ta różnorodność oznacza, że nie można oczekiwać, iż jeden moduł obsłuży wszystkie możliwości. Byłoby to trudne do osiągnięcia. Dlatego potrzeba całej rodziny modułów, przystosowanych do poszczególnych implementacji. Ogólna technika tworzenia i korzystania z modułów przystosowanych do wielokrotnego użycia musi to przewidywać.
51 Pięć wymagań dotyczących struktury modułu Niezależność reprezentacji – ogólna postać modułu powinna pozwalać klientom na określanie potrzebnych operacji bez konieczności znajomości ich implementacji. Przykład: Założenie – Moduł kliencki C wchodzący w skład aplikacji (np. program do zarządzania kapitałem, kompilator lub system informacji geograficznej) ma ustalić, czy określony element x występuje w tabeli t (zawierającej informacje o inwestycjach, słowa kluczowe lub nazwy miast). Realizacja – moduł C ma możliwość uzyskania informacji poprzez wywołanie present := has(t, x) Nie musi wiedzieć, jakiego rodzaju tabelą jest t (drzewem binarnym, tablicą mieszającą czy listą powiązaną). Autor modułu C musi jedynie wiedzieć, że t jest tabelą elementów określonego typu i x jest obiektem tego typu. Wybór algorytmu wyszukiwania, dostosowanego do implementacji t, jest zadaniem autora modułu zarządzającego tabelami. Chcemy, aby has automatycznie, w czasie wykonywania programu, dopasowywało się do tabeli t, nawet jeśli jej postać zmienia się z każdym wywołaniem.
52 Pięć wymagań dotyczących struktury modułu Wyodrębnianie wspólnych zachowań – moduł powinien być gotowy na wychwycenie wszelkich podobieństw, jakie mogą występować między implementacjami należącymi do tej samej rodziny. Różnorodność implementacji dostępnych dla niektórych problemów zazwyczaj będzie wymagała opracowania całej rodziny modułów. Wyzwanie polega tu na uniknięciu niepotrzebnego powielania operacji, to znaczy na oparciu działania modułu na operacjach wspólnych dla wszystkich wariantów.
53 Pięć wymagań dotyczących struktury modułu Wyodrębnianie wspólnych zachowań tabela tabela_sekwencyjna tabela_drzewiasta tabela_mieszająca tabela_plikowa tabela_powiązana tabela_tablicowa
54 Podział na podprogramy i pakiety Biblioteki podprogramów –Specyfikacja każdego problemu musi być prosta. Każdy problem musi dać się scharakteryzować za pomocą niewielkiego zbioru argumentów wejściowych i wyjściowych. –Problemy muszą wyraźnie różnić się od siebie. Wielokrotnie wykorzystuje się jakiś fragment projektu. –Nie mogą istnieć żadne złożone struktury danych (podprogramy korzystają z podprogramów). Pakiety –Pakiet jest strukturą językową, która ma swoją nazwę i jasno określony zakres. –Definicja każdego pakietu zawiera określoną liczbę deklaracji powiązanych ze sobą elementów, takich jak podprogramy i zmienne, nazywane cechami pakietu. –Każdy pakiet może precyzyjnie określać prawa dostępu, na podstawie których inne pakiety będą mogły korzystać z jego cech. Innymi słowy, mechanizm pakietów pozwala na ukrywanie informacji. –W językach kompilowanych każdy pakiet można kompilować niezależnie od pozostałych.
55 Przeciążanie Przeciążanie – to możliwość nadania określonej nazwie występującej w programie kilku różnych znaczeń. Najczęściej przeciąża się nazwy zmiennych. Ważniejsze jest przeciążenie podprogramów (operatorów – np. int a + int b, double a + double b), które pozwala stosować tą samą nazwę dla kilku podprogramów. has (t: „JAKIŚ_TYP_TABELI”, x: ELEMENT) Przeciążanie pozwala na stosowanie w kodzie źródłowym klienta tych samych zapisów przy stosowaniu różnych implementacji danego pojęcia.
56 Przeciążanie Znaczenie przeciążania Przeciążanie podprogramów jest możliwością stworzoną z myślą o klientach. Pozwala ono na stosowanie w kodzie źródłowym klienta tych samych zapisów przy stosowaniu różnych implementacji danego pojęcia. Przeciążanie składniowe (przeciążanie operatorów) Przeciążanie semantyczne (wiązanie dynamiczne)
57 Generyczność Generyczność to mechanizm pozwalający na definiowanie parametryzowalnych wzorców modułów, których parametry reprezentują typy. TABLE_HANDLING[G] – nazwa pakietu, gdzie G reprezentuje dowolny typ i jest tak zwanym generycznym parametrem formalnym. TABLE_HANDLING[INTEGER] TABLE_HANDLING[ACCOUNT] Np. INTEGER jest faktycznym parametrem generycznym, a proces uzyskiwania modułu ze wzorca nazywa się konkretyzacją generyczną. Generyczność pozwala na stosowanie w kodzie źródłowym dostawcy tych samych zapisów przy użyciu tych samych implementacji danego pojęcia, lecz odnoszących się do obiektów różnych typów.
58 Programowanie zorientowane obiektowo (1. definicja) Programowanie zorientowane obiektowo to sposób tworzenia oprogramowania, w którym architektura każdego systemu opierana jest na modułach wyprowadzonych z typów obiektów, na których system ten ma operować (a nie na funkcji bądź funkcjach, które mają się znaleźć w tym systemie). Motto obiektowości: Nie zaczynaj od pytania, co system ma robić, tylko na czym ma to robić!!!
59 Jak znajdować odpowiednie typy obiektowe? Wiele obiektów po prostu stanowi komputerowy model fizycznych obiektów znanych z codziennego życia – z dziedziny, do której odnosi się dany system. Źródłem typów obiektów mogą być też komponenty przystosowane do wielokrotnego użycia. Doświadczenie i naśladownictwo – czerpanie inspiracji z prac innych programistów.
60 Kryteria prawidłowego opisu obiektów Programowanie z dołu do góry. Opisy powinny być dokładne i jednoznaczne. Opisy powinny być wyczerpujące – przynajmniej na tyle, na ile jest to konieczne w danym przypadku. Opisy nie powinny być przesadnie szczegółowe.
61 Reprezentacje stosu
62 Abstrakcyjne postrzeganie obiektów Abstrakcja – w sztukach plastycznych: taka realizacja dzieła, w której jest ono pozbawione wszelkich cech ilustracyjności, a artysta nie stara się naśladować natury. Autorzy stosują różne środki wyrazu, dzięki którym "coś przedstawiają". Sztuka abstrakcyjna jest nazywana sztuką niefiguratywną. Jest to sztuka bardzo różnorodna, w której występują odrębne nurty, czasem związane z jednym tylko artystą. Abstrakcja (abstrahowanie) - proces tworzenia pojęć, w którym wychodząc od rzeczy jednostkowych (najczęściej konkretnych) dochodzi się do pojęcia bardziej ogólnego poprzez konstatowanie tego, co dla tych rzeczy wspólne (zazwyczaj właściwości). Ostatecznie drogą tego procesu dochodzi się do pojęć najuboższych w treść, ale o najszerszym zakresie, takich jak rzecz, przedmiot, substancja czy Byt. Pojęcie powstałe w wyniku procesu abstrakcji nazywamy abstraktem. Abstrakcją – w programowaniu nazywamy pewnego rodzaju uproszczenie rozpatrywanego problemu, polegające na ograniczeniu zakresu cech manipulowanych obiektów wyłącznie do cech kluczowych dla algorytmu, a jednocześnie niezależnych od implementacji. W tym sensie abstrakcja jest odmianą formalizmu matematycznego. Cel stosowania abstrakcji jest dwojaki: ułatwienie rozwiązania problemu i zwiększenie jego ogólności.
63 W przykładzie ze stosem, tym, co jednoczy wszystkie jego reprezentacje, niezależnie od różnic między nimi, jest fakt, że opisują one strukturę „pojemnikową” (strukturę, której przeznaczeniem jest przechowywanie innych obiektów), na której można wykonywać określone operacje i która ma pewne właściwości. Skupiając się nie na wyborze konkretnej reprezentacji, lecz na tych operacjach i właściwościach, możemy otrzymać abstrakcyjną, ale przydatną charakterystykę pojęcia stosu. Abstrakcyjne postrzeganie obiektów
64 Operacje, które zazwyczaj wykonuje się na stosie: polecenie służące do umieszczania elementu na wierzchołku stosu, put, polecenie służące do zdejmowania elementu z wierzchołka stosu, w przypadku gdy stos nie jest pusty, remove, zapytanie pozwalające sprawdzić, jaki element znajduje się na szczycie stosu, w przypadku gdy stos nie jest pusty, item, polecenie pozwalające sprawdzić, czy stos jest pusty (dzięki niemu klienci mogą zawczasu ustalić, czy wolno im wywołać polecenie remove lub item), empty, polecenie operacji tworzącej, która przygotuje (początkowo pusty stos), new. Abstrakcyjne postrzeganie obiektów
65 Specyfikacja abstrakcyjnego typu danych TYPES (typy) FUNCTIONS (funkcje) AXIOMS (aksjomaty) PRECONDITIONS (warunki początkowe)
66 Typ – jest to kolekcja obiektów charakteryzowanych przez funkcje, aksjomaty i warunki początkowe. Typ to zbiór obiektów. Typ STACK (stos) to zbiór wszystkich możliwych stosów, typ INTEGER to zbiór wszystkich możliwych wartości całkowitych, itd. TYPES – STACK [G] – specyfikacja dotyczy pojedynczego abstrakcyjnego typu danych STACK, opisującego stosy obiektów dowolnego typu G. G nazywamy generycznym parametrem formalnym abstrakcyjnego typu danych STACK, zaś o samym abstrakcyjnym typie danych STACK mówimy, że jest generyczny. Specyfikacja abstrakcyjnego typu danych
67 Funkcje – opisują wszystkie operacje, jakie można wykonać na egzemplarzach danego abstrakcyjnego typu danych. Są one podstawowym składnikiem każdej definicji typu. Opisują one egzemplarze typu nie przez pryzmat tego, czym one są, lecz tego, co mają do zaoferowania. FUNCTIONS –put: STACK [G] x G STACK [G] –remove: STACK [G] not STACK [G] –item: STACK [G] not G –empty: STACK [G] BOOLEAN –new: STACK [G] Specyfikacja abstrakcyjnego typu danych
68 AXIOMS (aksjomaty) – nie określa się wartości funkcji występujących w ATD, natomiast określa się właściwości tych wartości. Stąd wiadomo, że ATD określa np. stos STACK[G]. Dla każdego x: G, s: STACK[G], –A1, item(put(s,x)) = x –A2, remove(put(s,x)) = s –A3, empty(new) –A4, nie empty(put(s,x)) PRECONDITIONS – warunki początkowe określają dziedziny funkcji zdefiniowanych w ATD –remove(s: STACK[G]) require nie empty(s) –item(s: STACK[G]) require nie empty(s) Specyfikacja abstrakcyjnego typu danych
69 Definicja klasy Klasa jest to abstrakcyjny typ danych, wyposażony w implementacją, która może być częściowa. Klasę, która jest w pełni zaimplementowana, nazywamy konkretną. Klasę, która jest zaimplementowana tylko częściowo lub wcale, nazywamy abstrakcyjną. Każda klasa jest albo konkretna, albo abstrakcyjna.
70 Programowanie zorientowane obiektowo (2. definicja) Programowanie zorientowane obiektowo to technika tworzenia programów komputerowych, w której traktuje się je jako kolekcje (o ściśle określonej strukturze) implementacji (które mogą być częściowe) abstrakcyjnych typów danych.
71 Programowanie zorientowane obiektowo (2. definicja) Podstawą definicji jest pojęcie abstrakcyjnego typu danych. Do utworzenia programu są potrzebne nie tyle ATD, które są pojęciem matematycznym, co ich implementacje, należące do świata oprogramowania. Implementacje te nie muszą być kompletne. Wyrażenie „które mogą być częściowe” zostawia furtkę dla klas abstrakcyjnych, w tym dla ich skrajnej, całkowicie abstrakcyjnej postaci, w której nie mają one zaimplementowanych żadnych cech. System jest kolekcją klas, z których żadna nie jest szczególnie uprzywilejowana. Nie ma tu „góry” ani głównego podprogramu. Kolekcja ma ściśle określoną strukturę dzięki dwóm relacjom, jakie mogą zachodzić między klasami – dziedziczeniu i relacji dostawca-klient.
72 Klasa – struktura statyczna Klasa – to abstrakcyjny typ danych (ATD) wraz z całkowitą lub częściową implementacją. Klasa z pełną implementacją nazywana jest konkretną, a z niepełną – abstrakcyjną. Klasa jest typem – opisuje zbiór możliwych struktur danych, zwanych egzemplarzami klasy. ATD również posiadają egzemplarze. Różnica polega na tym, że egzemplarz ATD to element czysto matematyczny (element pewnego zbioru matematycznego), podczas gdy egzemplarz klasy to struktura danych, którą można przechowywać w pamięci komputera i manipulować nią w systemie oprogramowania. Produktem ubocznym definicji klasy jest definicja obiektu. Obiekt to po prostu egzemplarz jakiejś klasy. Na przykład egzemplarz klasy STACK reprezentujący pewien określony stos jest obiektem.
73 Klasa – struktura statyczna Klasa to kod programu. Jest ona statyczna – inaczej mówiąc – istnieje niezależnie od jakiegokolwiek działania. Z kolei obiekt pochodzący od tej klasy to dynamicznie stworzona struktura danych, istniejąca wyłącznie w pamięci komputera podczas działania systemu. Klasa jest modułem, czyli jednostką dekompozycji oprogramowania, ale także typem (albo w przypadku klasy o właściwościach generycznych, wzorcem typu). Treścią programów, które służą do tworzenia systemów (aplikacji) są klasy. Obiekty są pojęciem funkcjonującym jedynie w czasie wykonywania – oprogramowanie tworzy je i manipuluje nimi w czasie działania.
74 Jednolity system typów Reguła obiektowości Każdy obiekt jest egzemplarzem jakiejś klasy. Reguła obiektowości ma zastosowanie nie tylko do złożonych, zdefiniowanych przez programistę obiektów (takich jak struktury danych z kilkoma polami), ale do podstawowych obiektów, takich jak liczby całkowite, liczby rzeczywiste, wartości logiczne i znaki, które wszystkie będą traktowane jak egzemplarze predefiniowanych klas bibliotecznych (INTEGER, REAL, DOUBLE, BOOLEAN, CHARACTER).
75 Jednolity system typów Prosty i jednolity szkielet jest zawsze bardziej pożądany niż mnogość szczególnych przypadków. System typów w całości będzie opierał się na pojęciu klasy. Opisywanie podstawowych typów jako ATD, a tym samym jako klas jest proste i naturalne. Nie jest na przykład trudne dojście do tego, jak zdefiniować klasę INTEGER z cechami obejmującymi działania matematyczne, takie jak „+”, operacje porównania, takie jak „
76 Klasa POINT indexing description: „Punkty w przestrzeni dwuwymiarowej” class POINT feature x, y: REAL--Odcięta i rzędna rho: REAL is--Odległość od początku układu (0, 0) do Result := sqrt(x^2 + y^2) end theta: REAL is--Kąt tworzony z osią poziomą do … end distance(p: POINT): REAL is--Odległość do p do Result := sqrt((x – p.x)^2 + (y – p.y)^2) end
77 Klasa POINT translate(a, b: REAL) is --Przemieszcza poziomo o a i pionowo o b do x := x + a y := y + b end scale(factor: REAL) is--Skaluje według współczynnika factor do x := factor * x y := factor * y end rotate(p: POINT; angle: REAL) is --Obraca p wokół początku układu o kąt angle do … end
78 Klasa POINT Każdy abstrakcyjny typ danych, taki jak POINT, jest charakteryzowany przez zbiór funkcji, opisujący operacje mające zastosowanie do egzemplarzy ATD. W klasach (implementacjach ATD) funkcje są cechami – operacjami, które można stosować na egzemplarzach klasy. Są trzy rodzaje funkcji ATD: zapytania, polecenia i kreatory. Potrzebna jest podobna klasyfikacja cech, bazująca na tym, czy cecha jest implementowana przestrzenią, czy czasem. Cechy reprezentowane za pomocą przestrzeni – reprezentowane poprzez skojarzenie pewnej informacji z każdym egzemplarzem klasy. Takie cechy będą nazywane atrybutami. Dla punktów x i y to atrybuty w reprezentacji kartezjańskiej, a rho i theta to atrybuty w reprezentacji biegunowej. Cechy reprezentowane za pomocą czasu – reprezentowane poprzez zdefiniowanie jakiegoś obliczenia (algorytmu) obowiązującego dla wszystkich egzemplarzy klasy. Cechy te będą nazywane podprogramami. Dla punktów z klasy POINT rho i theta będą podprogramami w reprezentacji kartezjańskiej, a dla x i y podprogramami w reprezentacji biegunowej. Jeżeli podprogramy będą zwracać wynik nazwiemy je funkcjami. W klasie POINT zarówno x i y w reprezentacji biegunowej, jak rho i theta w reprezentacji kartezjańskiej są funkcjami, ponieważ wszystkie zwracają wynik typu REAL. Podprogramy, które nie zwracają wyników, odpowiadają poleceniom w specyfikacji ATD i nazywane są procedurami. Rozpatrywana klasa na przykład będzie zawierać procedury translate, rotate i scale.
79 Atrybuty i procedury Cecha PodprogramAtrybut ProceduraFunkcja Pamięć Obliczenia Brak wyniku Zwraca wynik p1.x
80 Bieżący egzemplarz - Current Kod klasy opisuje właściwości i zachowanie obiektów pewnego typu. Dokonuje tego, opisując właściwości i zachowanie typowego egzemplarza danego typu – bieżącego egzemplarza klasy. distance(p: POINT): REAL is--Odległość do p do if p /= Current then Result := sqrt((x – p.x)^2 + (y – p.y)^2) end Najczęściej egzemplarz bieżący jest niejawnie obowiązujący i nie trzeba odwoływać się do egzemplarza Current poprzez jego nazwę. Ale kim tak naprawdę jest Current?
81 Klienci i dostawcy W czystej postaci podejścia obiektowego, każdy element kodu przynależy do jakiejś klasy. Są dwa sposoby użycia klasy POINT: odziedziczenie klasy lub zostanie klientem tej klasy. Definicja klienta, dostawcy Niech S będzie klasą. Klasa C, która zawiera deklarację w postaci a:S, jest określana mianem klienta S. Klasa S staje się wówczas dostawcą klasy C. a może być atrybutem lub funkcją C albo też encją lokalną lub argumentem podprogramu C.
82 Klienci i dostawcy Przykład: -deklaracje x, y, rho, theta i distance czynią z klasy POINT klienta klasy REAL -inne klasy mogą z kolei stać się klientami POINT class GRAPHICS feature p1: POINT … some_routine is -- Wykonuje pewne działania na p1 do … Tworzy egzemplarz klasy POINT i związuje go z p1 … p1.translate(4.0, -1.5) … end … end
83 Klienci i dostawcy Zanim instrukcja p1.translate(4.0, -1.5) zostanie wykonana, atrybut p1 będzie miał wartość oznaczającą pewien egzemplarz klasy POINT. Możemy założyć, że egzemplarz ten reprezentuje początek układu współrzędnych o współrzędnych x=0 i y=0. O encji p1 mówimy, że jest związana z tym obiektem. 0.0 x y POINT
84 Wywołanie cechy Przykład wywołania cechy na rzecz obiektu p1.translate(4.0, -1.5) jest podstawowym mechanizmem obiektowego działania programów. p1 jest celem wywołania cechy. Skutek wywołania cechy f na obiekcie docelowym x Skutkiem wywołania jest zastosowanie cechy f na obiekcie związanym z x po zainicjalizowaniu każdego z formalnych argumentów f (jeżeli takie występują) wartościami odpowiadających im argumentów rzeczywistych. x.f x.f(u, v, …) x to encja lub wyrażenie, które w czasie wykonania zostanie związane z pewnym obiektem. x posiada pewien typ nadany przez klasę C, wówczas f musi być jedną z cech C. Dla x.f będzie to atrybut lub podprogram bez argumentów, dla x.f(u, v, …) musi być wyrażeniem odpowiadającym typowi i liczbie argumentów zadeklarowanych dla f w klasie C.
85 Zasada pojedynczego celu translate(p1, 4.0, -1.5) – wszystkie argumenty są traktowane tak samo W obiektowej formie wywołania nie obserwuje się takiej symetrii – wybieramy pewien obiekt (p1) jako cel wywołania, a pozostałe argumenty (4.0, -1.5) pełnią jedynie rolę pomocniczego rzutowania. Każde wywołanie staje się względne wobec pojedynczego obiektu docelowego i jest podstawowym elementem obiektowego przebiegu wykonania. Reguła pojedynczego celu Każda operacja w ramach obiektowego przebiegu wykonania odnosi się do jakiegoś obiektu, który jest bieżącym egzemplarzem w czasie wykonywania tej operacji
86 Tożsamość modułów i typów Jeżeli każdy moduł jest typem, to każda operacja w ramach modułu odnosi się do pewnego egzemplarza tego typu (bieżącego egzemplarza). Zależność między modułami a typami Możliwości udostępnione przez klasę POINT postrzeganą jako moduł to operacje, jakie można wykonywać na egzemplarzach klasy POINT postrzeganej jako typ. Zasada wywołania cechy F1 – Elementy programu są wykonywane tylko w ramach wywołania cechy F2 – Każde wywołanie odnosi się do jakiegoś obiektu docelowego
87 Rola egzemplarza Current Ponieważ każde wywołanie w podprogramie będzie odnosiło się do jakiegoś obiektu docelowego, wskazanego jawnie w wywołaniu, to w czasie wykonania każda nazwa cechy pojawiająca się w treści podprogramu będzie traktowana jak odnosząca się do tego właśnie celu. Przykład: p1.translate(4.0, -1.5) Każde wystąpienie x treści translate typu x:= x+a oznacza „x z p1”. Egzemplarz Current to bieżący obiekt docelowy wywołania. Tutaj Current będzie oznaczał obiekt związany z p1. W następnym wywołaniu Current będzie oznaczał obiekt docelowy tego wywołania.
88 Eksportowanie wybiórcze a ukrywanie informacji Pełna jawność: class S1 feature f … g … … end cechy f, g, … są dostępne dla wszystkich klientów S1.
89 Eksportowanie wybiórcze a ukrywanie informacji Zawężanie możliwości dostępu: class S2 feature f … g … feature {A, B} h … … end cechy f, g, … są dostępne dla wszystkich klientów S2, natomiast cecha h jest dostępna tylko dla klas A i B oraz ich potomków (klas, które dziedziczą pośrednio lub bezpośrednio po klasie A lub B).
90 Eksportowanie wybiórcze a ukrywanie informacji Całkowite ukrywanie cech klasy: class S3 feature { } i … … end cecha i jest ukryta przed wszystkimi klientami S3. Można ją zadeklarować jako eksportowaną do pustej listy klientów.