Инкапсуляция (компьютерное программирование) - Encapsulation (computer programming)

В объектно-ориентированном программировании (ООП) инкапсуляция означает связывание данных с методами, которые работают с этими данными, или ограничение прямого доступа к некоторым компонентам объекта. Инкапсуляция используется, чтобы скрыть значения или состояние объекта структурированных данных внутри класса , предотвращая прямой доступ к ним со стороны клиентов таким образом, чтобы можно было раскрыть скрытые детали реализации или нарушить неизменность состояния, поддерживаемую методами.

В классе обычно предоставляются общедоступные методы для более абстрактного доступа или изменения состояния. На практике иногда предоставляются методы (так называемые «геттеры» и «сеттеры» ) для косвенного доступа к значениям, но, хотя это не обязательно является нарушением абстрактной инкапсуляции, они часто считаются признаком потенциально плохого объектно-ориентированного программирования. (ООП) практика проектирования ( Антипаттерн ).

Этот механизм не является уникальным для ООП. Реализации абстрактных типов данных , например модули , предлагают аналогичную форму инкапсуляции. Сходство было объяснено теоретиками языков программирования в терминах экзистенциальных типов .

Значение

В объектно-ориентированных языках программирования и других связанных областях инкапсуляция относится к одному из двух связанных, но различных понятий, а иногда и к их комбинации:

  • Языковой механизм для ограничения прямого доступа к некоторым компонентам объекта .
  • Конструкция языка, которая упрощает связывание данных с методами (или другими функциями), работающими с этими данными.

Некоторые исследователи языков программирования и ученые используют первое значение отдельно или в сочетании со вторым как отличительную черту объектно-ориентированного программирования , в то время как некоторые языки программирования, которые обеспечивают лексические замыкания, рассматривают инкапсуляцию как функцию языка, ортогональную объектной ориентации.

Второе определение мотивировано тем фактом, что во многих объектно-ориентированных языках и других связанных областях компоненты не скрываются автоматически, и это может быть отменено; таким образом, сокрытие информации определяется как отдельное понятие теми, кто предпочитает второе определение.

Возможности инкапсуляции поддерживаются с использованием классов в большинстве объектно-ориентированных языков, хотя существуют и другие альтернативы.

Инкапсуляция и наследование

Авторы Design Patterns подробно обсуждают противоречие между наследованием и инкапсуляцией и заявляют, что, по их опыту, дизайнеры злоупотребляют наследованием. Они утверждают, что наследование часто нарушает инкапсуляцию, учитывая, что наследование предоставляет подклассу сведения о его родительской реализации. Как описано в проблеме йо-йо , чрезмерное использование наследования и, следовательно, инкапсуляции может стать слишком сложным и трудным для отладки.

Скрытие информации

Согласно определению, что инкапсуляция «может использоваться для сокрытия элементов данных и функций-членов», внутреннее представление объекта обычно скрыто от просмотра за пределами определения объекта. Как правило, только собственные методы объекта могут напрямую проверять его поля или управлять ими. Скрытие внутренних компонентов объекта защищает его целостность, не позволяя пользователям переводить внутренние данные компонента в недопустимое или несогласованное состояние. Предполагаемое преимущество инкапсуляции состоит в том, что она может снизить сложность системы и, таким образом, повысить надежность , позволяя разработчику ограничивать взаимозависимости между программными компонентами.

Некоторые языки, такие как Smalltalk и Ruby, разрешают доступ только через объектные методы, но большинство других (например, C ++ , C # , Delphi или Java ) предлагают программисту определенную степень контроля над тем, что скрыто, обычно с помощью таких ключевых слов, как publicи private. Стандарт ISO C ++ относится к protected, privateи publicкак « спецификаторы доступа » , и что они не «скрыть какую - либо информацию». Сокрытие информации достигается путем предоставления скомпилированной версии исходного кода, которая связана через файл заголовка.

Почти всегда есть способ переопределить такую ​​защиту - обычно через API отражения (Ruby, Java, C # и т. Д.), Иногда с помощью такого механизма, как изменение имени ( Python ) или использование специального ключевого слова, как friendв C ++. Системы, которые обеспечивают безопасность на основе возможностей объектного уровня (придерживаясь модели объектных возможностей ), являются исключением и гарантируют надежную инкапсуляцию.

Примеры

Ограничение полей данных

Такие языки, как C ++ , C # , Java , PHP , Swift и Delphi, предлагают способы ограничения доступа к полям данных.

Ниже приведен пример на C #, который показывает, как можно ограничить доступ к полю данных с помощью privateключевого слова:

class Program
{
    public class Account
    {
        private decimal accountBalance = 500.00m;

        public decimal CheckBalance()
        {
            return this.accountBalance;
        }
    }

    static void Main()
    {
        Account myAccount = new Account();
        decimal myBalance = myAccount.CheckBalance();

        /* This Main method can check the balance via the public
         * "CheckBalance" method provided by the "Account" class 
         * but it cannot manipulate the value of "accountBalance" */
    }
}

Ниже приведен пример на Java :

public class Employee {
    private BigDecimal salary = new BigDecimal(50000.00);
    
    public BigDecimal getSalary() {
        return this.salary;
    }

    public static void main() {
        Employee e = new Employee();
        BigDecimal sal = e.getSalary();
    }
}

Инкапсуляция также возможна в не объектно-ориентированных языках. В C , например, структура может быть объявлена ​​в общедоступном API через файл заголовка для набора функций, которые работают с элементом данных, содержащим элементы данных, которые недоступны для клиентов API с externключевым словом.

// Header file "api.h"

struct Entity;          // Opaque structure with hidden members

// API functions that operate on 'Entity' objects
extern struct Entity *  open_entity(int id);
extern int              process_entity(struct Entity *info);
extern void             close_entity(struct Entity *info);
// extern keywords here are redundant, but don't hurt.
// extern defines functions that can be called outside the current file, the default behavior even without the keyword

Клиенты вызывают функции API для выделения, работы и освобождения объектов непрозрачного типа данных . Содержимое этого типа известно и доступно только для реализации функций API; клиенты не могут получить прямой доступ к его содержимому. Исходный код этих функций определяет фактическое содержимое структуры:

// Implementation file "api.c"

#include "api.h"

struct Entity {
    int     ent_id;         // ID number
    char    ent_name[20];   // Name
    ... and other members ...
};

// API function implementations
struct Entity * open_entity(int id)
{ ... }

int process_entity(struct Entity *info)
{ ... }

void close_entity(struct Entity *info)
{ ... }

Изменение имени

Ниже приведен пример Python , который не поддерживает ограничения доступа к переменным. Однако по соглашению переменная, имя которой начинается с символа подчеркивания, должна считаться частной.

class Car: 
    def __init__(self) -> None:
        self._maxspeed = 200
 
    def drive(self) -> None:
        print(f"Maximum speed is {self._maxspeed}.")
 
redcar = Car()
redcar.drive()  # This will print 'Maximum speed is 200.'

redcar._maxspeed = 10
redcar.drive()  # This will print 'Maximum speed is 10.'

Смотрите также

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