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.