Hermetyzacja (programowanie komputerowe)

W systemach oprogramowania enkapsulacja odnosi się do łączenia danych z mechanizmami lub metodami, które działają na danych. Może również odnosić się do ograniczenia bezpośredniego dostępu do niektórych z tych danych, takich jak elementy składowe obiektu. Enkapsulacja umożliwia programistom przedstawienie spójnego i użytecznego interfejsu, który jest niezależny od tego, jak system jest implementowany wewnętrznie. Na przykład enkapsulacja może służyć do ukrywania wartości lub stanu obiektu danych strukturalnych wewnątrz klasy , uniemożliwiając klientom bezpośredni dostęp do nich w sposób, który mógłby ujawnić ukryte szczegóły implementacji lub naruszyć niezmienność stanu utrzymywaną przez metody.

Wszystkie systemy programowania obiektowego (OOP) obsługują enkapsulację, ale enkapsulacja nie jest unikalna dla OOP. Implementacje abstrakcyjnych typów danych , modułów i bibliotek , między innymi, oferują enkapsulację. Podobieństwo zostało wyjaśnione przez teoretyków języka programowania w kategoriach typów egzystencjalnych .

Oznaczający

W zorientowanych obiektowo językach programowania i innych pokrewnych dziedzinach enkapsulacja odnosi się do jednego z dwóch powiązanych, ale odrębnych pojęć, a czasem do ich kombinacji:

  • Mechanizm językowy do ograniczania bezpośredniego dostępu do niektórych komponentów obiektu .
  • Konstrukcja języka, która ułatwia łączenie danych z metodami (lub innymi funkcjami) operującymi na tych danych.

Niektórzy badacze języków programowania i naukowcy używają pierwszego znaczenia samodzielnie lub w połączeniu z drugim jako wyróżniającej cechy programowania obiektowego , podczas gdy niektóre języki programowania, które zapewniają domknięcia leksykalne, postrzegają enkapsulację jako cechę języka ortogonalną względem orientacji obiektowej.

Druga definicja jest motywowana faktem, że w wielu językach zorientowanych obiektowo i innych pokrewnych dziedzinach komponenty nie są automatycznie ukrywane i można to zmienić; dlatego ukrywanie informacji jest definiowane jako osobne pojęcie przez tych, którzy preferują drugą definicję.

Funkcje enkapsulacji są obsługiwane przy użyciu klas w większości języków zorientowanych obiektowo, chociaż istnieją również inne alternatywy.

Hermetyzacja i dziedziczenie

Autorzy Design Patterns szczegółowo omawiają napięcie między dziedziczeniem a enkapsulacją i stwierdzają, że z ich doświadczenia wynika, że ​​projektanci nadużywają dziedziczenia. Twierdzą, że dziedziczenie często łamie enkapsulację, biorąc pod uwagę, że dziedziczenie naraża podklasę na szczegóły implementacji jej rodzica. Jak opisano w problemie jo-jo , nadużywanie dziedziczenia, a tym samym enkapsulacja, może stać się zbyt skomplikowane i trudne do debugowania.

Ukrywanie informacji

Zgodnie z definicją, że enkapsulacja „może służyć do ukrywania elementów danych i funkcji składowych”, wewnętrzna reprezentacja obiektu jest generalnie ukryta przed widokiem poza definicją obiektu. Zazwyczaj tylko własne metody obiektu mogą bezpośrednio sprawdzać jego pola lub nimi manipulować. Ukrywanie wewnętrznych elementów obiektu chroni jego integralność, uniemożliwiając użytkownikom ustawienie wewnętrznych danych komponentu w nieprawidłowy lub niespójny stan. Przypuszczalną zaletą enkapsulacji jest to, że może zmniejszyć złożoność systemu, a tym samym zwiększyć niezawodność , umożliwiając programistom ograniczenie współzależności między składnikami oprogramowania. [ potrzebne źródło ]

Niektóre języki, takie jak Smalltalk i Ruby , umożliwiają dostęp tylko za pomocą metod obiektowych, ale większość innych (np. C++ , C# , Delphi lub Java ) oferuje programiście pewien stopień kontroli nad tym, co jest ukryte, zazwyczaj za pomocą słów kluczowych, takich jak public i private . Norma ISO C++ odnosi się do protected , private i public jako „ specyfikatorów dostępu ” i że nie „ukrywają żadnych informacji”. Ukrywanie informacji odbywa się poprzez dostarczenie skompilowanej wersji kodu źródłowego, który jest połączony za pośrednictwem pliku nagłówkowego.

Niemal zawsze istnieje sposób na obejście takiej ochrony – zwykle za pomocą refleksyjnego API (Ruby, Java, C# itp.), czasem przez mechanizm, taki jak zniekształcanie nazw ( Python ), lub użycie specjalnych słów kluczowych, takich jak friend w C++. Wyjątkiem są systemy, które zapewniają bezpieczeństwo oparte na możliwościach na poziomie obiektów (zgodnie z modelem możliwości obiektów ) i gwarantują silną enkapsulację.

Przykłady

Ograniczanie pól danych

Języki takie jak C++ , C# , Java , PHP , Swift i Delphi oferują sposoby ograniczania dostępu do pól danych.

Poniżej znajduje się przykład w języku C# , który pokazuje, jak można ograniczyć dostęp do pola danych za pomocą słowa kluczowego private :

 

      
    
            

          
        
             
        
    

      
    
            
           

        


    
 klasa  Program  {  public  class  Konto  {  prywatne  konto  dziesiętne Saldo   =  500,00  m  ;  publiczny  dziesiętny  CheckBalance  ()  {  zwróć  to  .  saldo konta  ;  }  }  static  void  Main  ()  {  Konto  moje konto  =  nowe  konto  ();  dziesiętne  moje saldo  =  moje konto  .  Sprawdź saldo  ();  /* Ta metoda Main może sprawdzić saldo za pomocą publicznej  * metody „CheckBalance” udostępnianej przez klasę „Account”  *, ale nie może manipulować wartością „accountBalance” */  }  } 

Poniżej znajduje się przykład w Javie :

   
         
    
       
         
    

        
            
           
    
 klasa  publiczna  Pracownik  {  prywatna  BigDecimal  pensja  =  nowa  BigDecimal  (  50000,00  );  public  BigDecimal  getSalary  ()  {  zwróć  to  .  wynagrodzenie  ;  }  public  static  void  main  ()  {  Pracownik  e  =  nowy  Pracownik  (); Duża   wartość  dziesiętna  =  e  .  pobierz wynagrodzenie  ();  }  } 

Hermetyzacja jest również możliwa w językach nieobiektywnych. Na przykład w C można zadeklarować strukturę w publicznym interfejsie API za pomocą pliku nagłówkowego dla zestawu funkcji, które działają na elemencie danych zawierającym składowe danych, które nie są dostępne dla klientów interfejsu API za pomocą słowa kluczowego extern .



           


      
                 
                

 // plik nagłówkowy "api.h"  struct  Entity  ;  // Nieprzezroczysta struktura z ukrytymi elementami  // Funkcje API działające na obiektach „Entity”  extern  struct  Entity  *  open_entity  (  int  id  );  extern  int  jednostka_procesu  (  struktura  jednostki  *  informacje  );  extern  void  close_entity  (  struct  Entity  *  info  );  // słowa kluczowe extern tutaj są zbędne, ale nie szkodzą.  // extern definiuje funkcje, które mogą być wywoływane poza bieżącym plikiem, domyślne zachowanie nawet bez słowa kluczowego 

Klienci wywołują funkcje API w celu przydzielania, operowania i zwalniania obiektów o nieprzezroczystym typie danych . Treści tego typu są znane i dostępne jedynie dla realizacji funkcji API; klienci nie mają bezpośredniego dostępu do jego zawartości. Kod źródłowy tych funkcji określa rzeczywistą zawartość struktury:



 

  
                  
           
        



    
  

   
  

   
   // Plik implementacji "api.c"  #include  "api.h"  struct  Entity  {  int  ent_id  ;  // numer identyfikacyjny  char  ent_name  [  20  ];  // Nazwa  ...  i  inni  członkowie  ...  };  // Implementacje funkcji API  struct  Entity  *  open_entity  (  int  id  )  {  ...  }  int  process_entity  (  struct  Entity  *  info  )  {  ...  }  void  close_entity  (  struct  Entity  *  info  )  {  ...  } 

Zniekształcenie nazwy

Poniżej znajduje się przykład Pythona , który nie obsługuje ograniczeń dostępu do zmiennych. Jednak konwencja jest taka, że ​​zmienna, której nazwa jest poprzedzona znakiem podkreślenia, powinna być uważana za prywatną.

  
       
          
 
       
        
 
  
  

  
   class  Car  :  def  __init__  (  self  )  ->  Brak  :  self  .  _maxspeed  =  200  def  drive  (  self  )  ->  Brak  :  print  (  f  "Maksymalna prędkość to  {  self  .  _maxspeed  }  ."  )  redcar  =  Samochód  ()  redcar  .  drive  ()  # Spowoduje to wydrukowanie komunikatu „Maksymalna prędkość to 200”.  czerwony  samochód  _maxspeed  =  10  czerwony samochód  .  drive  ()  # Spowoduje to wydrukowanie komunikatu „Maksymalna prędkość to 10”. 

Zobacz też