Gdy przychodzi potrzeba opakowania warstwy danych w inną warstwę danych, to mamy do czynienia z enkapsulacją, o której słów kilka w poniższym artykule.

Użyłem czasownika pakować, ponieważ "wizualnie" chyba najbardziej oddaje sens enkapsulacji. Najprostszym przykładem niech będzie ciąg znaków. String mieści się w tablicy, której ostatni element zakończony jest wartością 0. Aby sprawdzić jaką ma długość, należy ustalić na jakiej pozycji w tablicy znajduje się wartość zerowa. Można tego dokonać np. pętlą, która iteruje tak długo, dopóki nie napotka na koniec tablicy, a wartość iteratora jest wielkością stringu. Jeżeli zajdzie potrzeba, aby wyeliminować wielokrotne wykonywanie tej pętli sprawdzającej długość ciągu znaków, można przechować tę wartość w zmiennej i "dołączyć" ją do konstrukcji, która obok samego ciągu znaków, będzie udostępniać także jego długość. Jeżeli obie te informacje zawarte są w jednej strukturze, zachodzi enkapsulacja.

Najprostsza topografia enkapsulacji wyglądałaby następująco: Enkapsulacja logiczna. W momencie, gdy potrzebujemy ułożyć wiele danych w jedną strukturę, aby łatwiej tworzyć algorytmy, korzystające z tych danych. Poniżej klasyczny przykład z prostokątem. Prostokąt posiada długość i szerokość, a także przekątną (oraz wiele innych właściwości, jednak zatrzymajmy się na tych trzech). Można stworzyć prostokąt w następujący sposób:

#include <math.h> // dla funkcji pow() czyli potęga oraz sqrt() czyli pierwiastek kwadratowy
int prostokat_dlugosc = 10;
int prostokat_szerokosc = 5;
int prostokat_przekatna = sqrt(pow(protokat_dlugosc) + pow(prostokat_szerokosc));

Wszystko pięknie, jednak kiedy zajdzie potrzeba przekazania tych wartości do funkcji, będziemy musieli przekazywać osobno 3 parametry. Dodatkowo problem zajdzie, gdy będziemy chcieli stworzyć zmienne dla kolejnych prostokątów. Między innymi do radzenia sobie z takimi problemami powstały struktury (klasy, obiekty), które pozwalają zamykać zmienne w jednym logicznym pojemniku. Poniżej przykład dla języka C, gdzie najpierw trzeba zdefiniować typ takiej struktury:

typedef struct {
  int dlugosc;
  int szerokosc;
  int przekatna;
} prostokat_t; // tworzę typ prostokat_t, który jest strukturą zawierającą trzy zmienne typu int

Prostakat_t moj_prostakat;
moj_prostakat.dlugosc = 10;
moj_prostakat.szerogosc = 5;
moj_prostakat.przekatna = sqrt(pow(moj_prostakat.dlugosc) + pow(moj_prostakat.szerokosc));

Powyżej zamknąłem trzy zmienne do jednej struktury. Teraz mogę przekazywać jedynie tę strukturę jako argument do funkcji. Jest to wygodniejsze, kod jest bardziej przejrzysty, a co najważniejsze, można lepiej separować (w sensie logicznym) fragmenty algorytmów.

  1. Enkapsulacja ze względu na oszczędność pamięci. Ponieważ najmniejszą porcją danych, którą przetwarza procesor jest bajt, w niektórych przypadkach może okazać się to ogromnym marnotrawstwem. Wyobraźmy sobie, że posiadamy kokpit, w którym jest 5 przycisków. Każdy przycisk może być włączony albo wyłączony. Informacje o tych przyciskach chcemy przekazywać raz na sekundę do innego komputera. Jeżeli utworzymy zmienną dla każdego z tych przycisków i użyjemy najmniejszego rozmiaru zmiennej
    char
    , to co sekundę będziemy transmitować 5 bajtów danych. Ponieważ interesuje nas informacja 0 albo 1, która zmieści się w jednym bicie zmiennej, na każdej "marnujemy" 7 bitów (char zajmuje 1 bajt = 8 bitów). Informacje o wszystkich przyciskach (5 bitów) zmieszczą się w jednej zmiennej typu char. Należy "upchać" te informacje w jednej zmiennej, gdy to zrobimy, zamiast wysyłania 5 bajtów co sekundę wystarczy 1 bajt czyli ogromna oszczędność. W tym celu stosuje się operatory maski binarne. To może być temat na osobny artykuł, jednak aby nie być gołosłownym, zaprezentuję tutaj, jak mogłoby to wyglądać:
char przyciski = 0; // wszystkie wyłączone

przyciski = przyciski | (1 << 3); // włączam przycisk 4
przyciski = przyciski & ~(1 << 3); // wylączam przycisk 4

if (przyciski & 1 (<< 3) ) {
  // przycisk włączony
}
else {
 /// przycisk wyłączony
}

W powyższym przykładzie tworzę zmienną

char przyciski
. W kolejnej linii nakładam maskę o wartości 8 (binarnie 1000) i wykonuję binarną alternatywę, która ustawi wartość 4 bitu na 1, nie zmieniając pozostałych wartości. Pisemnie wyglądałoby to tak:


  00000000
| 00000100
  ----------
  00001000

Trzecia linijka tworzy maskę odwrotną do poprzedniej (binarnie 11110111) i wykonuje binarną koniunkcję, która "gasi" bit na pozycji 4 ustawiając go na zero. Następnie pokazuję jak można sprawdzić, czy konkretny bit (w tym przypadku 4) jest ustawiony na 1. Co do zapisu

1 << 3
. Jest to przesunięcie bitowe wartości
1
o 3 bity w prawo, czyli na czwartą pozycję.

Taka forma enkapsulacji wykorzystywana jest przy transmisji danych, np. w protokole TCP/IP, gdzie każdy bit ma znaczenie i każdy bajt wykorzystany jest do absolutnego maximum.

Procesem odwrotnym jest dekapsulacja, czyli rozpakowywanie danych z powrotem do ich pierwotnej formy. Inne określenia tego procesu to hermetyzacja i kapsułkowanie.

Jak Ty korzystasz z enkapsulacji?

Powiązane tematy

URL

URL

"W internecie jest wszystko." Do każdego zasobu jest tak samo daleko, wystarczy znać jego adres. Adres zasobu to ścieżka, która prowadzi dokładnie do tej rzeczy. W niej samej zakodowane jest sporo interesujących informacji. Czytaj całość

Aplikacje hybrydowe

Aplikacje hybrydowe

Problem pojawia się, gdy programista zaznajomiony z konkretną platformą staje przed zadaniem napisania "tego samego" na inną platformę. Wtedy jego wiedza może się okazać co najmniej niewystarczająca, a niekiedy nawet może przeszkadzać w poznawaniu nowego. Czytaj całość

KISS - porządek w kodzie

KISS - porządek w kodzie

Za każdym razem tworząc projekt od nowa, w głowie pojawia się piękna wizja czystego i czytelnego kodu, który tłumaczy sam siebie, jest lekki w zrozumieniu i łatwy w modyfikacji. Ostatecznie projekt kończy się zagmatwanym kodem, którego nie da się zrozumieć, nie czytając komentarzy. Kto nie był w takiej sytuacji niech pierwszy rzuci kamień. Czytaj całość


Piotr Poźniak

Piotr Poźniak

Programuję od ponad 15 lat. Prowadzę software house. Angażuję i zachęcam wszystkich do programowania w ramach inicjatywy Programowanie jest łatwe.

Bądź pierwszy, podziel się swoją opinią!

Obrazek przedstawiający nadgryzione ciasteczko