Obiektowe Języki Programowania Patryk Jasik Katedra Fizyki Teoretycznej i Informatyki Kwantowej Wydział Fizyki Technicznej i Matematyki Stosowanej Politechnika.

1 Obiektowe Języki Programowania Patryk Jasik Katedra Fiz...
Author: Aleksandra Piekarska
0 downloads 2 Views

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: poniedziałek 15-16, środa 16-17

2 Warunki zaliczenia przedmiotu Pisemny sprawdzian wiedzy z wykładu (10 pkt) Realizacja dwóch indywidualnych projektów programistycznych w języku C++ ISO/CLI (20 pkt) Sprawdzian wiedzy z programowania w języku C# (10 pkt) Uzyskanie 50% punktów spośród wszystkich możliwych do zdobycia Termin zaliczenia wykładu: ostatnie zajęcia w semestrze, 08.VI.2009 Terminy oddania projektów programistycznych: 29.III.2009 10.V.2009 Termin sprawdzianu z programowania: 10.VI.2009

3 Literatura I. Sommerville – „Inżynieria oprogramowania”, WNT, Warszawa 2003 B. Meyer – „Programowanie zorientowane obiektowo”, Helion 2005 www.moodle.pd.gda.pl – Proceduralne i obiektowe języki programowania 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

4 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

5 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

6 Uwagi techniczne – kompilatory i środowiska C++ –kompilator GNU –Dev-C++ –Microsoft Visual Studio 2005, 2008 –Borland C++ Builder Java –NetBeans –środowisko uruchomieniowe JRE wraz z JDK C# –Microsoft Visual Studio 2005, 2008 –Środowisko uruchomieniowe.NET, MONO lub DotGNU

7 Pierwszy program #include int main() { printf ("Witajcie! To jest wyklad z obiektowych jezykow programowania."); }

8 Pierwszy program #include using namespace std; int main() { cout

9 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); }

10 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

11 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

12 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.

13 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

14 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

15 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

16 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 Rozszerzalność – to możliwość łatwego dostosowywania programu komputerowego do zmian w specyfikacji Przystosowanie do wielokrotnego użycia – to zdolność elementów składowych oprogramowania do pełnienia roli elementów konstrukcyjnych wielu różnych aplikacji

17 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, tak jak w systemie operacyjnym Unix, w którym każdy plik tekstowy jest po prostu sekwencją znaków, –standaryzowane struktury danych, 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, 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.

18 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.

19 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

20 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.

21 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.

22 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.

23 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.

24 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.

25 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.

26 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.

27 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

28 Jakie elementy systemów nadają się do wielokrotnego wykorzystania? Personel Specyfikacje Projekty Wzorce projektowe Kody źródłowe Specjalistyczne komponenty Abstrakcyjne moduły

29 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

30 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.

31 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.

32 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ć.

33 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.

34 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.

35 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

36 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.

37 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.

38 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.

39 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ć!!!

40 Kryteria prawidłowego opisu obiektów Opisy powinny być dokładne i jednoznaczne. Opisy powinny być wyczerpujące – przynajmniej na tyle, na ile jest to konieczne w danym przypadku (być może, że zechcemy pominąć pewne detale). Opisy nie powinny być przesadnie szczegółowe.

41 Reprezentacje stosu

42 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.

43 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

44 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

45 Specyfikacja abstrakcyjnego typu danych TYPES (typy) FUNCTIONS (funkcje) AXIOMS (aksjomaty) PRECONDITIONS (warunki początkowe)

46 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

47 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

48 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.

49 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.

50 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.

51 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)

52 Jednolity system typów Reguła obiektowości Każdy obiekt jest egzemplarzem jakiejś klasy. Reguła obiektu 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).

53 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 „

54 Klasa POINT indexing description: „Punkty w przestrzeni dwuwymiarowej” class POINT feature x, y: REAL--Odcięta i rzędna (atrybuty) rho: REAL is--Odległość od początku układu (0, 0) do--podprogramy 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

55 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

56 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 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.

57 Atrybuty i procedury Cecha PodprogramAtrybut ProceduraFunkcja Pamięć Obliczenia Brak wyniku Zwraca wynik p1.x

58 Standardy języka C++ C++ ISO/ANSI – programy uruchamiane natywnie C++ CLI – programy dedykowane dla platformy.NET Framework

59 Platforma.NET Framework Dwa komponenty wzajemnie się uzupełniające: Common Language Runtime (CLR) – środowisko uruchomieniowe, w którym wykonywane są programy Zbiór bibliotek, zwanych bibliotekami klas środowiska.NET, dostarczające funkcje potrzebne do wykonywania kodu w CLR bez względu na użyty język programowania.

60 Standardy języka C++ Common Language Infrastructure – CLI Wspólna infrastruktura dla języków Microsoft Intermediate Language - MSIL Kod pośredni platformy.NET Common Type System - CTS Wspólny zbiór typów danych

61 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?

62 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:C, jest określana mianem klienta S. Klasa S staje się wówczas dostawcą klasy C.

63 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

64 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, …)

65 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. 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

66 Tożsamość modułów i typów 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

67 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.

68 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).

69 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.

70 Wieki Wybuch - oznaczenia 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 Każde wywołanie będzie miało jedno z następujących dwóch postaci: –niekwalifikowane – f(a, b, …) –kwalifikowane – x.g(u, v, …) Wywołanie występuje w treści podprogramu r. Jego wykonanie jest możliwe tylko jako element wywołania r. Załóżmy, że znamy obiekt docelowy wywołania, którym jest pewien obiekt OBJ. Wówczas obiekt docelowy t jest w każdym przypadku łatwy do ustalenia.

71 Wieki Wybuch - względność T1 – Dla postaci niekwalifikowanej t to po prostu OBJ. Przypadki T2, T3 i T4 odnoszą się do postaci kwalifikowanej. T2 – Jeżeli x jest atrybutem, to pole x obiektu OBJ ma wartość, która musi zostać związana z jakimś obiektem – obiektem tym jest właśnie t. T3 – Jeżeli x jest funkcją, to musimy najpierw wykonać (niekwalifikowane) wywołanie x. Funkcja zwróci t. T4 – Jeżeli x jest lokalną encją r, to wcześniejsze instrukcje nadały wartość x, która w chwili wywołania musi zostać związana z jakimś obiektem – obiektem tym jest właśnie t.

72 Wieki Wybuch - początek Definicja wykonania systemu Wykonanie obiektowego systemu oprogramowania składa się z następujących dwóch kroków: utworzenia pewnego obiektu, zwanego obiektem głównym dla danego wykonania, zastosowania na tym obiekcie określonej procedury, zwanej procedurą tworzącą. W chwili Wielkiego Wybuchu tworzone są obiekty i uruchamiana jest procedura tworząca. Obiekt główny jest egzemplarzem pewnej klasy, która jest klasą główną systemu. Procedura tworząca jest jedną z procedur klasy głównej. W większości systemów procedura tworząca sama wykreuje nowe obiekty i wywoła na nich procedury, wyzwalając kolejne utworzenia obiektów i kolejne wywołania. „Pokaz sztucznych ogni zaczynający się od jednej małej iskry”.

73 Wieki Wybuch - Current Pierwszym obiektem Current, od którego wszystko się zaczyna, jest obiekt główny. Na dowolnym etapie wykonania systemu, niech r będzie ostatnio wywołanym podprogramem. Jeżeli OBJ był bieżącym obiektem w chwili wywołania r, oto czym staje się Current: Jeżeli r wykonuje instrukcję, która nie wywołuje podprogramu (na przykład przypisanie), to obiektem bieżącym pozostaje ten sam obiekt. Zainicjowanie wywołania niekwalifikowanego również pozostawia ten sam obiekt obiektem bieżącym. Zainicjowanie kwalifikowanego wywołania x.f … sprawia, że obiekt docelowy tego wywołania, czyli obiekt związany z x, staje się nowym obiektem bieżącym. Po zakończeniu wywołania rolę obiektu Current ponownie przejmuje OBJ. W 2 i 3 przypadku wywołanie może odnosić się do podprogramu, który sam w sobie zawiera dalsze wywołania. Reguły te należy więc interpretować rekurencyjnie.

74 Systemy klas = gotowy do wykonania kod Aby stworzyć system klas potrzebujemy trzech elementów: zbioru klas CS, zwanego zbiorem klas systemu obrania którejś klasy ze zbioru CS jako klasy głównej wskazania procedury w klasie głównej, która jest procedurą tworzącą obiekt główny.