Инкапсуляция (программирование)

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску

Шаблон:Значения Шаблон:Не путать

Диаграмма объекта и его взаимодействия через методы, а не непосредственно с данными

Инкапсуляция (англ. Шаблон:Lang-en2, от Шаблон:Lang-lat) — в информатике, размещение в одном компоненте данных и методов, которые с ними работают. В реализации большинства языков программирования (C++, C#, Java и другие) обеспечивается механизм сокрытия, позволяющий разграничивать доступ к различным частям компонента.

Инкапсуляция зачастую рассматривается как понятие, присущее исключительно объектно-ориентированному программированию (ООП), но в действительности обширно встречается и в других (см. подтипизация на записях и полиморфизм записей и вариантов). В ООП инкапсуляция тесно связана с принципом абстракции данных (не путать с абстрактными типами данных, реализации которых предоставляют возможность инкапсуляции, но имеют иную природу). Это, в частности, влечёт за собой различия в терминологии в разных источниках. В сообществе C++ или Java, PHP принято рассматривать инкапсуляцию без сокрытия как неполноценную. Однако, некоторые языки (например, Smalltalk, Python) реализуют инкапсуляцию, но не предусматривают возможности сокрытия в принципе. Другие (Standard ML , OCaml) жёстко разделяют эти понятия как ортогональные и предоставляют их в семантически различном виде (см. сокрытие в языке модулей ML).

Подробности

Термин «инкапсуляция» может означать следующее в разных языках программирования:

  • механизм языка, ограничивающий доступ одних компонентов программы к другим;
  • языковая конструкция, связывающая данные с методами для их обработки.

Слово «инкапсуляция» происходит от латинского in capsula — «размещение в оболочке». Таким образом, инкапсуляцию можно интуитивно понимать как изоляцию, закрытие чего-либо инородного с целью исключения влияния на окружающее, обеспечение доступности главного, выделение основного содержания путём помещения всего мешающего, второстепенного в некую условную капсулу (чёрный ящик).

Примеры

Ada

Шаблон:Main <source lang="ada"> package Stacks is

 type Stack_Type is private;
 
 procedure Push (Stack : in out Stack_Type; Val : Integer);
 

private

 type Stack_Data is array (1 .. 100) of Integer;
 
 type Stack_Type is record
   Max : Integer := 0.3;
   Data : Stack_Data;
 end record;

end Stacks; </source>

C++

Шаблон:Main <source lang="cpp"> class A {

public:
  int a, b; //данные открытого интерфейса
  int Return_Something(); //метод открытого интерфейса
private:
  int Aa, Ab; //скрытые данные
  void Do_Something(); //скрытый метод

}; </source>

Класс А инкапсулирует свойства Aa, Ab и метод Do_Something(), представляя внешний интерфейс Return_Something, a, b.

C#

Шаблон:Main Целью инкапсуляции является обеспечение согласованности внутреннего состояния объекта. В C# для инкапсуляции используются публичные свойства и методы объекта. Переменные, за редким исключением, не должны быть публично доступными. Проиллюстрировать инкапсуляцию можно на простом примере. Допустим, нам необходимо хранить вещественное значение и его строковое представление (например, для того, чтобы не производить каждый раз конвертацию в случае частого использования). Пример реализации без инкапсуляции таков: <source lang="csharp">

   class NoEncapsulation
   {
       public double ValueDouble;
       public string ValueString;
   }

</source> При этом мы можем отдельно изменять как само значение Value, так и его строковое представление, и в некоторый момент может возникнуть их несоответствие (например, в результате исключения). Пример реализации с использованием инкапсуляции: <source lang="csharp">

   class EncapsulationExample
   {
       private double valueDouble;
       private string valueString;
       public double ValueDouble
       {
           get { return valueDouble; }
           set 
           {
               valueDouble = value;
               valueString = value.ToString();
           }
       }
       public string ValueString
       {
           get { return valueString; }
           set 
           {
               double tmp_value = Convert.ToDouble(value); //здесь может возникнуть исключение
               valueDouble = tmp_value;
               valueString = value;
           }
       }
   }

</source> Здесь доступ к переменным valueDouble и valueString возможен только через свойства ValueDouble и ValueString. Если мы попытаемся присвоить свойству ValueString некорректную строку и возникнет исключение в момент конвертации, то внутренние переменные останутся в прежнем, согласованном состоянии, поскольку исключение вызывает выход из процедуры.

Delphi

Шаблон:Main В Delphi для создания скрытых полей или методов их достаточно объявить в секции private.

<source lang="delphi">

 TMyClass = class
 private
   FMyField: Integer;
   procedure SetMyField(const Value: Integer);
   function GetMyField: Integer;
 public
   property MyField: Integer read GetMyField write SetMyField;
 end;

</source>

Для создания интерфейса доступа к скрытым полям в Delphi введены свойства.

PHP

Шаблон:Main <source lang="php"> class A {

   private string $a; // скрытое свойство
   private int $b; // скрытое свойство
   private function doSomething(): void //скрытый метод
   {
       //actions
   }
   public function returnSomething(): int //открытый метод
   {
       //actions
   }

} </source>

В этом примере у класса А закрыты свойства $a и $b с целью предотвращения повреждения этих свойств другим кодом, которому необходимо предоставить только права на чтение.

Java

Шаблон:Main В Java инкапсуляция понимается как механизм, связывающий код и данные, которыми он манипулирует, защищая оба этих компонента от внешнего вмешательства и злоупотреблений. Инкапсуляцию можно считать защитной оболочкой, которая предохраняет код и данные от произвольного доступа со стороны другого кода, находящегося снаружи оболочки. Доступ к коду и данным, находящимся внутри оболочки, строго контролируется тщательно определённым интерфейсом. В Java основой инкапсуляции является класс<ref>Шаблон:Книга</ref>. <source lang="java" line="1"> class First {

private int a;
private int b;
private void doSomething() { //скрытый метод
 //actions
}
public int getSomething() { //открытый метод
 return a;
} 

} </source>

JavaScript

Шаблон:Main <source lang="javascript" line="1"> let A = function() {

// private
let _property;
let _privateMethod = function() { /* actions */ } // скрытый метод
// public
this.getProperty = function() { // открытый интерфейс
 return _property;
}
this.setProperty = function(value) { // открытый интерфейс
 _property = value;
 _privateMethod();
}

} </source> или <source lang="javascript" line="1"> let A = function() {

// private
let _property;
let _privateMethod = function() { /* actions */ } // скрытый метод
// public
return {
 }
}

</source>или используя приватные свойства<source lang="javascript" line="1"> class A {

   #property;
   #privateMethod = () => {
       /* actions */
   }
   
   get property() { // геттер
       return this.#property;
   }
   set property(value) { // сеттер
       this.#property = value;
   }

} </source>

Шаблон:Примечания

Шаблон:Rq