Kolejna kartka z terminologii programistycznej! Jeżeli interesuje Cię na czym polega niejaki paradygmat w programowaniu, to zapraszam Cię do środka artykułu, w którym wyjaśnimy sobie sam termin i wymienimy najważniejsze paradygmaty jakie występują ⭐!

PARADYGMAT W PROGRAMOWANIU. MOŻESZ NIE WIEDZIEĆ, ŻE WIESZ CZYM ON JEST 🙂

Pisząc kod, nieważne w jakim języku, "z urzędu" korzystasz z jakiegoś paradygmatu. Możesz to przedstawić na kodzie źródłowym albo wizualnie, a zwykle dużo ciężej ze zdefiniowaniem własnymi (i prostymi) słowami 🙂.

Czytelniku mój, paradygmat to inaczej sposób "rozłożenia" kodu programu ℹ️. Określa on "spojrzenie" programisty na przebieg wykonywania instrukcji i w zależności od języka, który narzuca swoją składnię, definiuje odpowiednią postać aplikacji 💻. Stąd też jedną aplikację można napisać na kilka różnych "rozłożeń" kodu źródłowego. Możemy podzielić go na klasy i obiekty (podejście obiektowe np. Java) albo na procedury (podejście proceduralne np. C).

Oczywiście możemy miksować różne paradygmaty w pewnych częściach aplikacji, o ile język wspiera określony paradygmat. C++ na przykład, wspiera pisanie proceduralne (pisanie jak w C), natomiast silnie wspiera też podejście obiektowe, funkcyjne i uogólnione, co czyni go elastycznym zawodnikiem 💪.

Rodzaje paradygmatów

Opiszę Ci teraz pokrótce czym się charakteryzują poszczególne paradygmaty. Wymieniłem te najważniejsze, lecz możesz w innych źródłach trafić na jeszcze inne 🙂.

Obiektowy

Programowanie obiektowe jest jednym z najpopularniejszych podejść do kodu źródłowego. Jest najbardziej intuicyjny dla nas, ludzi, ponieważ z natury interpretujemy otaczającą nas rzeczywistość w charakterze obiektów, a każdy z nich ma swój stan i określone zachowania. Wiemy, że bankomat jest zdolny wypłacać pieniądze, długopis pisać po papierze, a domofon powiadamiać nas efektem dźwiękowym, gdy ktoś wciśnie guzik. Jest to po prostu intuicyjne 💡!

Paradygmat obiektowy zobaczysz w takich językach, jak Java czy C#, w których rolą główną jest definiowanie klas (poniżej składnia Javy):

public class MyClass {
	public void doSomething() {
		// instrukcje
	}
}

i tworzenie instancji na ich podstawie:

MyClass myClassInstance = new MyClass();
Funkcyjny

Podejście funkcyjne polega na operowaniu na ciągach wywołań różnych funkcji, aby na końcu tego "sznurka" otrzymać jakiś ostateczny rezultat, unikając przy tym wielu rozgałęzień (instrukcje warunkowe), pętli i modyfikowania danych po drodze.

Charakterystycznymi elementami programowania funkcyjnego są wyrażenia lambda i funkcje wyższego rzędu (więcej informacji znajdziesz w załączonych artykułach).

Paradygmat funkcyjny wspierany jest między innymi przez C#, a przykładem może być zdefiniowanie metody (jako funkcji wyższego rzędu), która jako parametr oczekuje definicji procedury. Taki efekt uzyskasz dzięki "Action":

public void DoSomething(Action action)
{
	action?.Invoke();
}

a w trakcie wywoływania, ustalasz co ma się wykonać:

DoSomething(() => Console.WriteLine("Wykonuję akcję."));

Drugim charakterystycznym elementem podejścia funkcyjnego jest wywoływanie ciągu metod. Tak można zrobić używając biblioteki LINQ na liście liczb, dzięki czemu otrzymujemy listę liczb podzielnych przez 4 w prostym ciągu jednowierszowym:

var numbers = new List<int>() {3, 4, 5, 10, 18, 35};
var numbersDivisibleByFour = numbers.Where(number => number % 4 == 0).ToList();
Strukturalny

Strukturalne podejście oznacza tyle, że korzystamy w kodzie z pętli, unikając jak ognia tzw. instrukcji skoku ("goto"), która sięga korzeni języka asemblera ("JMP").

Prosty przykład w języku C sumujący liczby od 1 do 20:

#define NUMBERS_COUNT 20

#include <stdio.h>

int main(void)
{
	int sum = 0;

	for (int i = 1; i <= NUMBERS_COUNT; ++i)
	{
		sum += i;
	}

	printf("%d\n", sum);
	
	return 0;
}

Za pomocą dyrektywy "define", tworzę sobie stałą całkowitoliczbową do ustalania limitu liczb. Można też użyć słowa "const".

Niestrukturalny

Przeciwieństwem podejścia strukturalnego jest niestrukturalne, czyli wykorzystywanie wspomnianych instrukcji skoku, zamiast pętli. Ten sam przykład co u góry, tylko "w ujęciu" niestrukturalnym (język C wspiera instrukcję "goto", gdybyś nie wiedział(a) 😁):

#define NUMBERS_COUNT 20

#include <stdio.h>

int main(void)
{
	int sum = 0;
	int i = 1;
	
count:
	sum += i;

	if(++i <= NUMBERS_COUNT)
	{
		goto count;
	}

	printf("%d\n", sum);
	
	return 0;
}
Imperatywny

Programowanie imperatywne (wiem, trudne słowo 😀), przekładając na polski, oznacza pisanie kodu ujawniającego krok po kroku co on robi celem osiągnięcia danego efektu końcowego. Odpowiada na pytanie: "co mam zrobić?".

Przykład teraz będzie w języku C#, który sumuje wszystkie liczby zmiennoprzecinkowe w danej liście:

var numbers = new List<float> {3.14f, 5.2f, 1.18f, 17.95f};
var sum = 0f;

foreach (var number in numbers)
{
	sum += number;
}

Console.WriteLine(sum);

W tym wypadku, kluczowym fragmentem paradygmatu imperatywnego jest jawne sumowanie elementów:

sum += number;

gdyż to jest instrukcja, która "odsłania" swoją intencję (odpowiada na zadane pytanie "co robić?").

Deklaratywny

Deklaratywny paradygmat jest całkowitym przeciwieństwem imperatywnego. Odpowiada na pytanie: "w jaki sposób mam to zrobić?", a użyte instrukcje nie ujawniają szczegółów implementacji. Weźmy jeszcze raz ten sam przykład z góry, tylko wg podejścia deklaratywnego:

var numbers = new List<float> {3.14f, 5.2f, 1.18f, 17.95f};

Console.WriteLine(numbers.Sum());

Mamy to samo - zsumowanie liczb zmiennoprzecinkowych. Natomiast tym razem mamy użycie metody "Sum", która to robi, lecz nie wiemy co dokładnie się dzieje wiersz po wierszu (mamy tylko nazwę metody mówiącą nam o intencji). I na tym polega różnica!

Uogólniony

Żeby szybko zrozumieć paradygmat uogólniony, wystarczy jedno pojęcie: typ generyczny...i wszystko jasne 😄!

W tym podejściu chodzi o użycie tzw. "typu ogólnego" stosowanego najczęściej w kolekcjach, dzięki którym możemy do jednego "zbiornika" wrzucać elementy o odpowiednim typie danych. Wstawia się w kod typ T (najczęściej stosowana konwencja nazewnicza) i podczas tworzenia instancji klasy bądź wywoływania metody wykorzystującej typ generyczny, określamy jaki dokładnie typ ma "stać" za tajemniczym T.

Prosty przykład to język Java i utworzenie listy typu "ArrayList":

ArrayList<String> strings = new ArrayList<>();

Typ "String" wewnątrz nawiasów kątowych, to typ ściśle określony w momencie tworzenia listy, w miejscu typu T (ogólnego).

Samo zagadnienie typu generycznego opisałem w odrębnym artykule dla:

Więc po szczegóły zapraszam serdecznie do odpowiedniego odnośnika ❤️!

Wizualny

Ostatni o jakim chcę wspomnieć, to paradygmat wizualny. Jest to podejście niezwiązane z kodem źródłowym i zamiast niego, koncentrujemy się na budowie przepływu programu operując na WYSIWYG, czyli "otrzymujesz to, co widzisz". Chodzi o korzystanie z opracowanych wcześniej elementów "opakowanych" w abstrakcyjne bloki typu "Rozpocznij dialog z...", "Czy koliduje z...?" lub "Zniszcz obiekt".

Przykłady narzędzi, jakie obsługują wizualny paradygmat, to między innymi:

Paradygmat wizualny w programowaniu

Paradygmat wizualny polega na tworzeniu aplikacji poprzez umieszczanie bloków z gotowymi implementacjami opatrzonymi abstrakcyjnymi hasłami. Obraz dotyczy bloków z narzędzia "Scratch".

Jak sam(a) widzisz, nie ma jednego podejścia tworzenia aplikacji. Nie jest też nigdzie napisane, że jeden jest zły, a drugi zawsze dobry. Zależy od języka, zależy od upodobania. Twoim zadaniem jest odkryć wszystkie paradygmaty i kierować się tym, który przemawia przez Ciebie najbardziej 🌞!


Nie ma to jak szczęśliwe zakończenie 😊. Temat paradygmatu został wyjaśniony 👍!

PODOBNE ARTYKUŁY