Главная
Новости
Строительство
Ремонт
Дизайн и интерьер

















Яндекс.Метрика

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

Инкапсуляция (англ. encapsulation, от лат. in capsula) — в информатике, процесс разделения элементов абстракций, определяющих ее структуру (данные) и поведение (методы); инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации. На практике это означает, что класс должен состоять из двух частей: интерфейса и реализации. В реализации большинства языков программирования (C++, C#, Java и другие) обеспечивается механизм сокрытия, позволяющий разграничивать доступ к различным частям компонента.

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

Подробности

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

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

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

Примеры

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;

C++

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

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

C#

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

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

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

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; } } }

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

Delphi

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

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

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

PHP

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

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

Java

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

JavaScript

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

или

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

или используя приватные свойства

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