Podstawowe pojęcia programowania obiektowego

Czym jest programowanie obiektowe (OOP)?

Programowanie obiektowe (ang. Object-Oriented Programming) to paradygmat programowania, w którym program jest modelowany jako zbiór obiektów. Każdy obiekt reprezentuje element rzeczywistości (np. samochód, ucznia, książkę), posiada właściwości i zachowania (czyli metody). Obiekty te współpracują ze sobą, wykonując operacje, które pozwalają na rozwiązanie konkretnego problemu.

Główne pojęcia programowania obiektowego:

  • Klasa: Szablon lub plan dla obiektów.
  • Obiekt: Konkretna instancja klasy.
  • Dziedziczenie: Mechanizm, który pozwala jednej klasie dziedziczyć cechy innej klasy.
  • Polimorfizm: Możliwość traktowania różnych obiektów w podobny sposób, gdy mają wspólną cechę.
  • Enkapsulacja: Ukrywanie szczegółów implementacyjnych obiektu i zapewnianie dostępu do nich tylko poprzez interfejs.
  • Abstrakcja: Skupienie się na ważnych cechach obiektu i ukrywanie szczegółów.

1. Klasa

Klasa to podstawowy element w programowaniu obiektowym. Jest to szablon lub schemat, według którego tworzone są obiekty. Klasa określa, jakie właściwości i metody będą miały obiekty stworzone na jej podstawie.

Klasy opisują cechy (np. właściwości) i zachowania (np. metody) rzeczywistości, które są modelowane w programie. Na przykład, klasa „Samochód” mogłaby mieć właściwości takie jak marka, model, rok produkcji oraz metody takie jak jazda, zatrzymanie, zmiana biegów.

Ważne cechy klas:

  • Właściwości (pola) – czyli dane przechowywane przez obiekt (np. imię, wiek, kolor).
  • Metody – czyli operacje, jakie obiekt może wykonywać (np. ruszanie, zatrzymywanie się, liczenie).
  • Konstruktor – specjalna metoda, która jest wywoływana, gdy tworzony jest nowy obiekt. Inicjalizuje ona właściwości obiektu.

2. Obiekt

Obiekt to konkretna instancja klasy. Innymi słowy, obiekt to rzeczywisty przykład klasy, który istnieje w pamięci komputera i ma określone wartości dla swoich właściwości.

Każdy obiekt posiada:

  • Stan: reprezentowany przez wartości jego właściwości.
  • Zachowanie: definiowane przez metody, które można wywołać na obiekcie.

Obiekty są centralnym punktem programowania obiektowego, ponieważ to na nich wykonywane są operacje w programie. Klasy opisują, jak obiekty mają wyglądać i co mogą robić, ale to obiekty są faktycznie używane w programie.

3. Dziedziczenie

Dziedziczenie to mechanizm, który pozwala jednej klasie (nazywanej klasą pochodną) przejąć właściwości i metody innej klasy (nazywanej klasą bazową). Dzięki dziedziczeniu możemy ponownie wykorzystać kod, co zmniejsza potrzebę powtarzania tych samych instrukcji w różnych miejscach programu.

Klasa pochodna „dziedziczy” wszystkie elementy klasy bazowej, ale może też dodać nowe elementy lub zmodyfikować istniejące. Dziedziczenie pozwala tworzyć hierarchię klas, w której bardziej ogólne klasy są na wyższych poziomach, a bardziej szczegółowe na niższych.

Główne cechy dziedziczenia:

  • Reużywalność kodu: Klasa pochodna może korzystać z funkcji i właściwości klasy bazowej, bez konieczności ich ponownego definiowania.
  • Rozszerzanie funkcjonalności: Klasa pochodna może dodawać nowe właściwości i metody, rozszerzając działanie klasy bazowej.
  • Polimorfizm: Dzięki dziedziczeniu można traktować obiekty różnych klas pochodnych w taki sam sposób (omówione w kolejnym punkcie).

4. Polimorfizm

Polimorfizm to zdolność obiektów różnych klas do reagowania na te same polecenia (metody) w różny sposób. Mechanizm ten pozwala na stosowanie tej samej nazwy metody w różnych klasach, co upraszcza i ujednolica kod, nawet jeśli metoda wykonuje różne operacje w zależności od obiektu, na którym jest wywoływana.

Polimorfizm można podzielić na dwa główne rodzaje:

  • Polimorfizm statyczny (kompilacyjny) – realizowany za pomocą przeciążania metod, gdzie metoda o tej samej nazwie ma różne parametry.
  • Polimorfizm dynamiczny (wykonawczy) – realizowany za pomocą dziedziczenia i przesłaniania metod, gdzie metoda w klasie pochodnej może mieć inne działanie niż metoda o tej samej nazwie w klasie bazowej.

Polimorfizm umożliwia używanie kodu bardziej ogólnego, który działa na różnych typach obiektów, co zwiększa elastyczność i reużywalność kodu.

5. Enkapsulacja (Hermetyzacja)

Enkapsulacja (inaczej hermetyzacja) to proces ukrywania szczegółów implementacyjnych obiektu i zapewniania dostępu do tych danych tylko za pośrednictwem zdefiniowanego interfejsu (najczęściej metod publicznych). Dzięki enkapsulacji programista może ograniczyć dostęp do pewnych właściwości lub metod obiektu, zapewniając ochronę jego wewnętrznego stanu.

W enkapsulacji wyróżniamy:

  • Pola prywatne: Dane obiektu, do których nie ma bezpośredniego dostępu z zewnątrz klasy.
  • Metody publiczne: Zdefiniowane funkcje, które umożliwiają kontrolowany dostęp do pól prywatnych.
  • Właściwości (properties): W C# często używane są właściwości, które pozwalają na łatwiejszy dostęp do prywatnych pól poprzez zdefiniowanie specjalnych metod dostępu (gettery i settery).

Enkapsulacja chroni dane obiektów przed nieautoryzowanymi modyfikacjami, co zwiększa stabilność i bezpieczeństwo aplikacji.

6. Abstrakcja

Abstrakcja to pojęcie, które odnosi się do ukrywania zbędnych szczegółów implementacyjnych i skupienia się tylko na najważniejszych cechach obiektu. Dzięki abstrakcji programista może tworzyć bardziej ogólny kod, który może być wykorzystywany w różnych sytuacjach, bez znajomości szczegółów działania każdej z klas.

Abstrakcję osiągamy za pomocą:

  • Klas abstrakcyjnych – są to klasy, które zawierają deklaracje metod bez ich implementacji. Klasy pochodne muszą te metody zaimplementować.
  • Interfejsów – interfejs definiuje zbiór metod, które muszą zostać zaimplementowane przez klasy, które ten interfejs implementują.

Abstrakcja pozwala uprościć pracę programisty, skupiając się na tym, co obiekt robi, a nie jak to robi.

7. Interfejsy i klasy abstrakcyjne

Interfejsy i klasy abstrakcyjne to narzędzia, które pomagają w osiągnięciu zarówno polimorfizmu, jak i abstrakcji.

  • Interfejs to zbiór deklaracji metod i właściwości, które muszą być zaimplementowane przez klasy, które go implementują. Interfejsy nie zawierają żadnej logiki, tylko określają, jakie funkcje powinien posiadać obiekt.
  • Klasa abstrakcyjna to klasa, której nie można instancjonować bezpośrednio. Może zawierać zarówno zdefiniowane, jak i abstrakcyjne metody, które muszą być zaimplementowane przez klasy pochodne.

Różnica między nimi polega na tym, że interfejs jest bardziej ogólny (wszystkie metody są abstrakcyjne), a klasa abstrakcyjna może zawierać zarówno metody z implementacją, jak i abstrakcyjne.