– Cześć, Amigo! Na dzisiejszej lekcji będziemy zajmować się enkapsulacją. W tej chwili masz na ten temat dość ogólne pojęcie.

Enkapsulacja - 1

A zatem, jakie są jej zalety? Jest ich wiele, ale wymienię cztery, które są według mnie najważniejsze:

1) Prawidłowy stan wewnętrzny.

Programy najczęściej posiadają wiele klas, które wchodzą w interakcje z tym samym obiektem. Kiedy jednocześnie wchodzą one w interakcje z wewnętrznymi danymi tego obiektu, może to naruszyć integralność jego danych i sprawić, że nie będzie on działał prawidłowo.

Obiekt powinien zatem śledzić wszelkie zmiany jego wewnętrznych danych, a jeszcze lepiej by było, gdyby on sam dokonywał tych zmian.

Jeśli nie chcemy, aby zmienna danej klasy została zmieniona przez inną klasę, to deklarujemy ją jako private, co oznacza, że dostęp do niej mogą mieć tylko metody tej klasy. Jeśli chcemy, by inne klasy widziały zmienne w trybie „tylko do odczytu”, to należy do nich dodać getter zadeklarowany jako public.

Chcemy, aby każdy mógł się dowiedzieć, ile elementów zawiera nasza kolekcja, ale równocześnie nie życzymy sobie, aby ktokolwiek dokonywał w niej zmian bez naszej zgody. W tym przypadku deklarujemy zmienną private int count i metodę public getCount().

Prawidłowa enkapsulacja gwarantuje, że inne klasy nie będą miały bezpośredniego dostępu do wewnętrznych danych naszej klasy, a zatem nie będą mogły jej zmieniać bez naszej kontroli. Muszą one wywoływać metody na klasie, zawierającej zmienne, które mają zostać zmienione.

Najlepiej jest założyć, że inni programiści będą używać Twoich klas w taki sposób, jaki najbardziej odpowiada im samym, a nie w taki, jaki jest najbezpieczniejszy dla Ciebie (bądź Twojej klasy). Jest to źródłem błędów, ale można tego uniknąć.

2) Sprawdzanie parametrów.

Czasami należy sprawdzić parametry przekazane do metod Twojej klasy. Załóżmy, na przykład, że mamy pewną klasę o nazwie „osoba”, gdzie możemy dookreślić daty urodzenia zawartych w niej osób. Powinniśmy sprawdzić, czy wszystkie przekazane dane odpowiadają logice programu i klasy. Nie mamy przecież 13. miesiąca bądź 30. dnia lutego itp.

– Ale dlaczego ktoś miałby podać dzień 30 lutego jako datę swoich urodzin?

– No cóż, po pierwsze, każdy może popełnić błąd podczas wprowadzania danych.

Po drugie, mimo że program chodzi jak w zegarku, to i tak może zawierać błędy. Może wydarzyć się na przykład coś takiego.

Programista pisze kod ustalający, kto pojutrze ma urodziny. Powiedzmy, że dziś jest 3 marca. Program dodaje 2 do dzisiejszej daty i szuka tych, którzy urodzili się 5 marca. Jak dotąd, wszystko jest w porządku.

Ale kiedy nadchodzi dzień 30 marca, program nie znajduje nikogo urodzonego 32 marca. Programy zawierają dużo mniej błędów, kiedy metody przeprowadzają sprawdzanie parametrów.

– Pamiętam, że kiedy uczyłem się o ArrayList, widziałem kod, który zawierał w metodach get i set sprawdzenie tego, czy parametr indeksu jest większy bądź równy zero i mniejszy niż długość tablicy. Jeśli zostałby znaleziony element nieodpowiadający indeksowi, kod wyrzuciłby błąd.

– Tak, to właśnie klasyczne sprawdzanie danych wejściowych.

3) Mniej błędów podczas zmiany kodu wewnątrz klas.

Załóżmy, że napisałeś pewną bardzo pomocną klasę – część wielkiego projektu. Wszyscy programiści tak ją polubili, że zaczęli jej używać w setkach miejsc we własnym kodzie.

Wiadomo już, że klasa jest użyteczna, więc decydujesz się ją udoskonalić. – Ale jeśli pozbędziesz się jakichkolwiek metod w tej klasie, kod innych programistów nie będzie już się kompilował. Programiści będą musieli szybko go zmodyfikować. A im częściej coś się zmienia, tym większe ryzyko błędów. I jeśli będziesz regularnie coś psuł, to Cię znienawidzą.

Ale jeśli zmieniać będziemy metody oznaczone jako prywatne, to wiemy, że nie będą one wywoływane w żadnym cudzym kodzie. Możemy je pisać na nowo, zmieniać liczbę i typ parametrów, a zależny kod wciąż będzie działał. A przynajmniej będzie się kompilował.

4) Definiujemy, w jaki sposób inne obiekty mają wchodzić w interakcje z naszym obiektem.

Możemy dokładnie określić, jakie działania mogą być wykonywane na naszym obiekcie. Na przykład, możemy chcieć, aby została utworzona tylko jedna instancja klasy — nawet, jeśli jest ona tworzona jednocześnie w wielu miejscach projektu. A to możemy osiągnąć, używając enkapsulacji.

Enkapsulacja - 2

Enkapsulacja pozwala nam nakładać dodatkowe restrykcje, z których mogą wynikać dodatkowe profity. Na przykład klasa String zostaje zaimplementowana jako niezmienny (niemutowalny) obiekt. Instancje klasy String nie mogą być zmieniane od momentu ich utworzenia aż do ich zniszczenia. Wszystkie metody klasy String (remove, substring, ...) zwracają nowy ciąg i w żaden sposób nie zmieniają obiektu, na którym są wywoływane.

– Kurka wodna! A więc tak to wszystko działa!

– Enkapsulacja jest naprawdę intrygująca.

– W pełni się z Tobą zgadzam.