Rodzaje metod programowania. Paradygmat programowania (ang

advertisement
Rodzaje metod programowania.
Paradygmat programowania (ang. programming paradigm) — wzorzec programowania
komputerów przedkładany w danym okresie rozwoju informatyki ponad inne lub ceniony
w pewnych okolicznościach lub zastosowaniach.
Paradygmat programowania definiuje sposób patrzenia programisty na przepływ sterowania
i wykonywanie programu komputerowego. Przykładowo, w programowaniu obiektowym jest on
traktowany jako zbiór współpracujących ze sobą obiektów, podczas gdy w programowaniu
funkcyjnym definiujemy, co trzeba wykonać, a nie w jaki sposób.
Różne języki programowania mogą wspierać różne paradygmaty programowania. Przykładowo,
Smalltalk i Java są ściśle zaprojektowane dla potrzeb programowania obiektowego, natomiast
Haskell jest językiem funkcyjnym. Istnieją także języki wspierające kilka paradygmatów, np.
Common Lisp oraz Python.
Wiele paradygmatów jest dobrze znanych z tego, jakie praktyki są w nich zakazane, a jakie
dozwolone. Ścisłe programowanie funkcyjne nie pozwala na tworzenie skutków ubocznych.
W programowaniu strukturalnym nie korzysta się z instrukcji skoku (goto). Częściowo z tego
właśnie powodu nowe paradygmaty są uważane za zbyt ścisłe przez osoby przyzwyczajone do
wcześniejszych stylów. Jednakże takie omijanie pewnych technik znacznie ułatwia
przeprowadzanie dowodów o poprawności programu, albo po prostu zrozumienia jego działania,
bez ograniczania samego języka programowania.
Zależności między paradygmatami programowania mogą przybierać skomplikowane formy,
ponieważ jeden język może wspierać wiele różnych paradygmatów. Na przykład, C++ posiada
elementy programowania proceduralnego, obiektowego oraz uogólnionego, co stanowi o nim, że
jest hybrydowym językiem. To projektanci i programiści decydują, jak zbudować z nich wszystkich
w pełni działający program. Niektórzy decydują się na ścisłe programowanie proceduralne,
natomiast inni łączą ze sobą elementy wielu paradygmatów w zależności od potrzeb.
Przykłady paradygmatów promowania:
• proceduralne
• strukturalne
• funkcyjne
• imperatywne
• obiektowe
• uogólnione
• sterowane zdarzeniami
• logiczne (np. Prolog)
• aspektowe (np. AspectJ)
• deklaratywne
• agentowe
• modularne
Programowanie proceduralne to paradygmat programowania zalecający dzielenie kodu na
procedury, czyli fragmenty wykonujące ściśle określone operacje. Procedury nie powinny korzystać
ze zmiennych globalnych (w miarę możliwości), lecz pobierać i przekazywać wszystkie dane (czy
też wskaźniki do nich) jako parametry wywołania.
Programowanie strukturalne to paradygmat programowania zalecający hierarchiczne
dzielenie kodu na bloki, z jednym punktem wejścia i jednym lub wieloma punktami wyjścia.
Chodzi przede wszystkim o nieużywanie (lub ograniczenie) instrukcji skoku (goto). Dobrymi
strukturami są np. instrukcja warunkowe (if, if...else), pętle (while, repeat), wyboru (case, ale nie
switch z C i potomnych). Strukturalność zakłócają instrukcje typu: break, continue, switch (w C
itp.), które jednak w niektórych przypadkach znacząco podnoszą czytelność kodu. Praktycznie w
każdym języku można programować strukturalnie, jednakże w niektórych jest to styl naturalny (np.
w Pascalu).
Programowanie funkcyjne (lub programowanie funkcjonalne) – filozofia i metodyka
programowania będąca odmianą programowania deklaratywnego, w której funkcje należą do
wartości podstawowych, a nacisk kładzie się na wartościowanie (często rekurencyjnych) funkcji, a
nie na wykonywanie poleceń. W czystym programowaniu funkcyjnym, raz zdefiniowana funkcja
zwraca zawsze tę samą wartość dla danych wartości argumentów, tak jak funkcje matematyczne.
Programowanie imperatywne – paradygmat programowania, który opisuje proces
wykonywania jako sekwencję instrukcji zmieniających stan programu. Podobnie jak tryb
rozkazujący w lingwistyce wyraża żądania jakichś czynności do wykonania. Programy
imperatywne składają się z ciągu komend do wykonania przez komputer. Rozszerzeniem (w sensie
wbudowanych funkcji) i rodzajem (w sensie paradygmatu) programowania imperatywnego jest
programowanie proceduralne.
Programowanie obiektowe (ang. object-oriented programming) — paradygmat
programowania, w którym programy definiuje się za pomocą obiektów — elementów łączących
stan (czyli dane, nazywane najczęściej polami) i zachowanie (czyli procedury, tu: metody).
Obiektowy program komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się
pomiędzy sobą w celu wykonywania zadań.
Programowanie uogólnione (lub generyczne, z ang. generic programming) – jeden z
paradygmatów programowania. Programowanie uogólnione pozwala na pisanie kodu programu bez
wcześniejszej znajomości typów danych, na których kod ten będzie pracował. Obecnie wiele
języków programowania ma możliwość wykorzystywania uogólnień, np. C++, D, Java oraz
Haskell. W językach C++ czy D programowanie uogólnione umożliwiają szablony. W językach
Java, C#, Visual Basic .NET, Haskell, Eiffel służą do tego typy generyczne (lub inaczej
uogólnione).
Programowanie sterowane zdarzeniami (Programowanie zdarzeniowe) – Jest to
paradygmat programowania, według którego program jest cały czas bombardowany zdarzeniami
(events), na które musi odpowiedzieć, i że przepływ sterowania w programie jest całkowicie
niemożliwy do przewidzenia z góry. Programowanie sterowane zdarzeniami jest mocno powiązane
ze środowiskami wieloprocesowymi (nie mylić z komputerami wieloprocesorowymi), z
graficznymi środowiskami systemów operacyjnych oraz z programowaniem obiektowym.
Programowanie logiczne (nazywane także programowaniem w logice lub
programowaniem w języku logiki) to będąca odmianą programowania deklaratywnego metoda
programowania, w której program podawany jest jako pewien zestaw zależności, a obliczenia są
dowodem pewnego twierdzenia w oparciu o te zależności. Językiem wyspecjalizowanym w takim
programowaniu jest Prolog
Programowanie aspektowe (aspect-oriented programming, AOP) to paradygmat tworzenia
programów komputerowych wspomagający separację zagadnień i rozdzielenie programu na części
w jak największym stopniu niezwiązane funkcjonalnie. Najbardziej popularne aspektowe
rozszerzenie dla języka Java - AspectJ.
Programowanie deklaratywne — rodzina paradygmatów programowania, które nie są z
natury imperatywne. W przeciwieństwie do programów napisanych imperatywnie, programista
opisuje warunki, jakie musi spełniać końcowe rozwiązanie (co chcemy osiągnąć), a nie
szczegółową sekwencję kroków, które do niego prowadzą (jak to zrobić). Przykładami
programowalnych języków deklaratywnych są języki funkcyjne i logiczne takie, jak Ocaml, XSLT
czy Prolog. Przykładem języka opisowego jest SQL.
Programowanie agentowe - kolejny poziom abstrakcji programowania, wyższy od
abstrakcji programowania obiektowego. Polega on na tworzeniu agentów (ang. Software Agent).
Programowanie modularne (ang. modular programming) — paradygmat programowania
zalecający stosowanie nadrzędności modułów w stosunku do procedur i bloków tworzących
program. Moduł grupuje funkcjonalnie związane ze sobą dane oraz procedury i jest reprezentacją
obiektu jednokrotnie występującego w programie. Programowanie takie wykorzystuje
wyspecjalizowane języki programowania, np. Ada, Modula-2, Pascal, Fortran90.
Programowanie obiektowe dokładniej.
Programy definiuje się za pomocą obiektów — elementów łączących stan (czyli dane, nazywane
najczęściej polami) i zachowanie (czyli procedury, tu: metody). Obiektowy program
komputerowy wyrażony jest jako zbiór takich obiektów, komunikujących się pomiędzy sobą w celu
wykonywania zadań.
Obiekty są częściami różnych klas Klasa jest częściową lub całkowitą definicją dla obiektów.
Definicja obejmuje dopuszczalny stan obiektów oraz ich zachowania. Obiekt, który został
stworzony na podstawie danej klasy nazywany jest jej instancją. Klasy mogą być typami języka
programowania - przykładowo, instancja klasy Owoc będzie mieć typ Owoc. Klasy posiadają
zarówno interfejs, jak i strukturę. Interfejs opisuje, jak komunikować się z jej instancjami za
pośrednictwem metod, zaś struktura definiuje sposób mapowania stanu obiektu na elementarne
atrybuty.
Instancjonowanie klasa nie jest samodzielnym bytem, lecz szablonem do tworzenia
nowych obiektów określonego typu i posiadających określone zachowanie. Obiekt utworzony na
podstawie danej klasy nazywany jest jej instancją, a proces jego tworzenia – instancjonowaniem.
Poszczególne instancje klasy posiadają ten sam zbiór zachowań i atrybutów, lecz różnią się
przechowywanymi w nich wartościami.
Przykładowo, klasa Samochód opisuje pojęcie „samochodu“ poprzez wymienienie
charakteryzujących go atrybutów: prędkości maksymalnej, mocy silnika, producenta czy modelu.
Jednak dwie różne instancje tej klasy będą różnić się od siebie wartościami tych atrybutów: jeden
samochód może mieć prędkość maksymalną 220 km/h, zaś drugi - 240 km/h.
Struktura oprócz interfejsu, klasa definiuje także strukturę danych przechowywanych w
obiektach. Są one dzielone na elementarne atrybuty, zwane także polami lub właściwościami. Zbiór
wartości wszystkich atrybutów tworzy stan konkretnego obiektu, który przechowywany jest w
pamięci lub innym nośniku danych.
Interfejs Obiekty wchodzą w interakcje ze światem zewnętrznym poprzez metody.
Określają one możliwe zachowania, jakie na obiekcie można wykonać, a ich definicje znajdują się
w klasie danego obiektu. Metoda jest rodzajem podprogramu języka programowania z dodatkową
właściwością, tj. dostępem do atrybutów obiektu, na którym została wywołana. Metody mogą
zarówno odczytywać, jak i modyfikować atrybuty obiektu, dlatego określane są także mianem
„zachowań“. Zbiór metod, którymi dysponuje obiekt, nazywany jest jego interfejsem.
W przykładzie z samochodem klasa może definiować następujące metody: jedź, hamuj, skręć lub
aktualna Prędkość. Część z nich wpływa na aktualny stan obiektu, powodując np. zatrzymanie
pojazdu, zaś inne służą wyłącznie do uzyskiwania dodatkowych informacji.
Elementy statyczne Część języków dopuszcza tworzenie tzw. metod oraz atrybutów
statycznych. Nie są one związane z żadnym konkretnym obiektem klasy, lecz tworzą globalny stan
oraz globalnie dostępne operacje, które można wywoływać nawet wtedy, gdy nie posiadamy żadnej
instancji klasy.
Rodzie klas:
Klasy właściwe to każda klasę, która może być instancjonowana.
Klasy abstrakcyjne to przeciwieństwo klasy właściwej - nie można utworzyć obiektu takiej klasy.
Ma ona zastosowanie jedynie wtedy, gdy język programowania obsługuje dziedziczenie. Klasa
abstrakcyjna stanowi wtedy wzorzec do dalszego rozszerzenia, który sam w sobie nie może być
pełnoprawnym, poprawnym obiektem.
Klasa finalna ma sens jedynie w przypadku dziedziczenia - nazywamy tak klasę, której nie można
rozszerzyć.
Podstawowe założenia paradygmatu obiektowego
Istnieje pewna różnica zdań co do tego, jakie cechy języków programowania czynią je
obiektowymi. Powszechnie uważa się, że najważniejsze są następujące cechy:
• Abstrakcja jest to 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.
• Hermetyzacja (inna używana nazwa to enkapsulacja, (ang.) encapsulation) polega na
ukrywaniu pewnych danych składowych lub metod obiektów danej klasy tak, aby były one
dostępne tylko metodom wewnętrznym danej klasy lub funkcjom zaprzyjaźnionym. Gdy
dostęp do wszystkich pól danej klasy jest możliwy wyłącznie poprzez metody, lub inaczej
mówiąc: gdy wszystkie pola w klasie znajdują się w sekcji prywatnej lub chronionej, to taką
hermetyzację nazywa się hermetyzacją pełną.
• Polimorfizm (z gr. wielopostaciowość) - mechanizmy pozwalające programiście używać
wartości, zmiennych i podprogramów na kilka różnych sposobów. Inaczej mówiąc jest to
możliwość wyabstrahowania wyrażeń od konkretnych typów.
• Dziedziczeniem (ang. inheritance) w programowaniu obiektowym nazywamy mechanizm
współdzielenia funkcjonalności między klasami. Klasa może dziedziczyć po innej klasie, co
oznacza, że oprócz swoich własnych atrybutów oraz zachowań, uzyskuje także te
pochodzące z klasy, z której dziedziczy. Klasa dziedzicząca jest nazywana klasą pochodną
lub potomną (w j. angielskim: subclass lub derived class), zaś klasa, z której następuje
dziedziczenie — klasą bazową (w ang. superclass). Z jednej klasy bazowej można uzyskać
dowolną liczbę klas pochodnych. Klasy pochodne posiadają obok swoich własnych metod i
pól, również kompletny interfejs klasy bazowej.
Dziedziczenie pojedyncze i dziedziczenie wielokrotne w programowaniu obiektowym
wyróżniane jest dziedziczenie pojedyncze oraz dziedziczenie wielokrotne. Z dziedziczeniem
pojedynczym mamy do czynienia, gdy klasa pochodna dziedziczy po dokładnie jednej klasie
bazowej (oczywiście klasa bazowa wciąż może dziedziczyć z jakiejś innej klasy), natomiast w
dziedziczeniu wielokrotnym klas bazowych może być więcej. Wielokrotne dziedziczenie jest
obsługiwane w takich językach, jak C++, Common Lisp czy Perl.
Modelowanie obektowe.
Download