image


Определение


Значение термина «инкапсуляция» расплывчато и отличается от источника к источнику. Принято считать, что инкапсуляция?—?один из основополагающих принципов ООП, хотя некоторые научные статьи вовсе упускают инкапсуляцию из списка. К примеру, Джон Митчелл в книге «Концепты в языках программирования» при перечислении основных концептов в ООП упоминает только абстракцию?—?термин который принято считать близким к инкапсуляции по значению, но все-же более обширным и высокоуровневым. С другой стороны, Роберт Мартин в его книге «Чистая архитектура» явно говорит о том, что инкапсуляция, наследование и полиморфизм считается фундаментом ООП.


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


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

Инкапсуляция как связь


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


#!/usr/bin/python3

class Phone:
    number = "111-11-11"
    def print_number(self):
        print( "Phone number is: ", self.number )

my_phone = Phone()
my_phone.print_number()

input( "Press Enter to exit" )

Класс “Phone” объединяет данные в переменной “number” с методом “print_number()”


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


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


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


  • публичными (public)?—?данные доступны всем;
  • приватными (private)?—?данные доступны только объекту/классу которому они принадлежат.

Большинство языков имеют дополнительные степени доступа, которые находятся между этими границами. К примеру, в C++ и Python3 есть три уровня доступа: публичный, защищенный и приватный; C# добавляет ключевое слово «внутренний» (internal) в список.


Стоит отметить, что в большинстве языков программирования, уровень доступа к любым данным установлен по умолчанию. Например, в C++ по умолчанию уровень доступа к данным в классе задан как приватный—?к его данным могут обращаться только члены и друзья класса. Стандартный уровень доступа к структуре (struct) в C++ отличается?—?он публичный, и данные в такой структуре могут быть доступны любому. Уровень доступа для переменных и методов класса в Python 3 полностью зависит от синтаксиса.


Примеры


Инкапсуляция


Python 3 предоставляет 3 уровня доступа к данным:


  • публичный (public, нет особого синтаксиса, publicBanana);
  • защищенный (protected, одно нижнее подчеркивание в начале названия, _protectedBanana);
  • приватный (private, два нижних подчеркивания в начала названия, __privateBanana).

Для краткости и простоты, только два базовых уровня (приватный и публичный) освещены в примере.


#!/usr/bin/python3

class Phone:
    username = "Kate"                # public variable
    __how_many_times_turned_on = 0   # private variable

    def call(self):                  # public method
        print( "Ring-ring!" )

    def __turn_on(self):             # private method
        self.__how_many_times_turned_on += 1 
        print( "Times was turned on: ", self.__how_many_times_turned_on )

my_phone = Phone()

my_phone.call()
print( "The username is ", my_phone.username )
# my_phone.turn_on()
# my_phone.__turn_on()
# print( “Turned on: “, my_phone.__how_many_times_turned_on)
# print( “Turned on: “, my_phone.how_many_times_turned_on)
# will produce an error
input( "Press Enter to exit" )

Доступ к публичным переменным и методам можно получить из основной программы. Попытка получить приватные данные или запустить приватный метод приведет к ошибке.


Нарушение инкапсуляции


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


#!/usr/bin/python3

class Phone:
    username = "Kate"                # public variable
    __serial_number = "11.22.33"     # private variable
    __how_many_times_turned_on = 0   # private variable

    def call(self):                  # public method
        print( "Ring-ring!" )

    def __turn_on(self):             # private method
        self.__how_many_times_turned_on += 1 
        print( "Times was turned on: ", self.__how_many_times_turned_on )

my_phone = Phone()

my_phone._Phone__turn_on()
my_phone._Phone__serial_number = "44.55.66"
print( "New serial number is ", my_phone._Phone__serial_number )

input( "Press Enter to exit" )

Несколько слов о Магии


Существуют методы, так называемые «магические методы» («magic methods») или «специальные методы» («special methods»), которые позволяют классам определять свое поведение в отношении стандартных языковых операторов. Примером таких языковых операторов могут служить следующие выражения:


  • x > y
  • x[ i ]

Python 3 поддерживает множество таких методов, полный список можно найти на странице официальной документации языка. __init__ (инициализатор) является наиболее часто используемым из них и запускается при создании нового объекта класса. Другой, __lt__ (расширенное сравнение), определяет правила для сравнения двух объектов пользовательского класса. Такие методы не попадают в категорию «приватных» или «публичных», поскольку служат другим целям и корнями глубоко уходят во внутреннюю структуру языка.


#!/usr/bin/python3

class Phone:
    def __init__(self, number):      # magic method / inititalizer
        print( "The Phone object was created" )
        self.number = number

    def __lt__(self, other):         # magic method / rich comparison
        return self.number < other.number

my_phone = Phone(20)
other_phone = Phone(30)

if my_phone < other_phone:
    print( "Two instances of custom class were compared" )
    print( "'__lt__' was called implicitly" )

if my_phone.__lt__(other_phone):
    print( "Now, '__lt__' was used explicitly" )

input( "Press Enter to exit" )

Магические методы могут быть вызваны любым пользователем таким же образом как и любой публичный метод в Питоне, однако они предназначены для неявного использования в своих особых случаях. Специальный случай для метода __init__?—?инициализация нового объекта класса. __lt__ служит для сравнения двух объектов.


Заключение


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


Источники


  1. John C. Mitchell, Concepts in programming languages
  2. Robert C. Martin, Clean Architecture, A Craftsman’s Guide to Software Structure and Design

Комментарии (10)


  1. AN3333
    19.03.2019 11:11
    -2

    Значение термина «инкапсуляция» расплывчато и отличается от источника к источнику… К примеру, Джон Митчелл… С другой стороны, Роберт Мартин ...

    А слабо посмотреть первоисточник?


    1. netricks
      19.03.2019 12:04
      +1

      Первоисточник мало чем отличается по ценности от остальных источников. Со времен первоисточника концепция ООП улучшалась и переосмысливалась.


  1. sirius23
    20.03.2019 15:52

    +


  1. microcoder
    20.03.2019 23:59

    Значение термина «инкапсуляция» расплывчато и отличается от источника к источнику

    Почему расплывчато? Инкапсуляция от англ. encapsulation и от лат. in capsula, то есть что-то в капсуле (коробочке). Далее не трудно вообразить некую коробочку (класс), сверху которой есть только какие-то кнопки управления (публичные методы), а в целом весь механизм скрыт от пользователя (программиста который использует класс).
    В данном случае, любой класс в котором есть хотя бы одна переменная и один метод который ею управляет наглядно демонстрирует этот принцип

    class Phone:
        number = "111-11-11"
        def print_number(self):
            print( "Phone number is: ", self.number )
    


    Мне кажется, что здесь как раз таки нет принципа инкапсуляции, поле number открыто и доступно из вне. Можно вызвать метод, а можно обратится к полю = получим один и тот же результат, стало быть ничего не сокрыто (не инкапсулировано).


    1. KaterynaBondarenko Автор
      21.03.2019 01:15

      Почему расплывчато?

      Потому как существенно отличается от источника к источнику.

      Если рассматривать инкапсуляцию как сокрытие данных от пользователя — да, вы абсолютно правы, как данные так и метод открыты и доступны. Если использовать ваше определение, «группировка + сокрытие», опять таки, в этом примере данные и метод не скрыты (не инкапсулированы).

      Этот пример иллюстрирует определеное значение термина «инкапсуляция» — «группировка данных и методов которые ими управляют в одно целое». В этом значении речи о сокрытии не идет, и доступ к данным не существеннен.


    1. fireSparrow
      21.03.2019 14:20
      +1

      Почему расплывчато? Инкапсуляция от англ. encapsulation и от лат. in capsula, то есть что-то в капсуле (коробочке). Далее не трудно вообразить некую коробочку (класс), сверху которой есть только какие-то кнопки управления (публичные методы)

      Мне кажется, что здесь как раз таки нет принципа инкапсуляции

      Если для понимания значения некоторого термина нужно привлекать фантазию, аналогии, субъективные ассоциации и аргумент «мне кажется, что», то это и значит, что термин расплывчато определён.


      1. microcoder
        21.03.2019 16:24

        Если для понимания значения некоторого термина нужно привлекать фантазию, аналогии, субъективные ассоциации и аргумент «мне кажется, что»

        Интересное заявление. С "мне кажется" согласен, это было лишнее в моём предложении, надо было более увереннее писать.


        Но всё, что вы перечислили нужно исключать, чтобы получить понимание о термине? А как собственно понимать остаётся? Зубрёжкой?


        В теориях получается нет терминов, так как их нельзя понимать по-вашему, так как для этого нужно привлекать всё, что вы перечислили?


        термин расплывчато определён

        Он не может быть в принципе быть расплывчатым или не расплывчатым. Не существует таких у него свойств. Расплывчатость лежит в границах только отдельно конкретно взятой личности и за пределы его понимания не выходит. У кого-то расплывчато, а у кого то не расплывчато. Тогда как Вы определите, расплывчат он сам по себе термин или нет?


        1. fireSparrow
          21.03.2019 16:44

          Все эти вещи хороши, если они помогают понять уже существующее чёткое определение. Но если кроме них ничего нет, то каждый как хочет, так и толкует.

          Вот, например, ваш пример с коробочкой. Вы представили себе коробочку, увидели в своём воображении, что содержимое в ней спрятано, и пришли к выводу, что инкапсуляция — это сокрытие и ограничение доступа.
          Я представил себе ту же коробочку, но увидел прежде всего то, что она — контейнер, который позволяет удобно держать в одном месте несколько вещей. И для меня инкапсуляции — это группировка логически связанных данных и методов.

          Кто из нас двоих прав? А этого нельзя сказать, если у нас нет чёткого определения, а только картинка с коробочкой.

          Мне кажется, что здесь как раз таки нет принципа инкапсуляции

          А вот мне, исходя из моего понимания инкапсуляции, кажется, что есть.
          И никаких аргументов, кроме «мне кажется» и «ну представьте себе коробочку», ни вы мне не сможете привести, ни я вам. Мы можем спорить до второго пришествия, и каждый останется при своём мнении. Ergo, термин определён крайне расплывчато.


          1. microcoder
            21.03.2019 20:40

            Кто из нас двоих прав?

            Правильного ответа не существует до тех пор, пока кто-то не получит осознание с помощью той или иной версии, он же и определит, кто прав лично для него. Для другого правда может быть другой.
            Я привел пример своей версии и выразил своё мнение, что термин для меня лично не размыт, совершенно чёткий.


            Мы можем спорить до второго пришествия, и каждый останется при своём мнении.

            Совершенно верно. Правда у каждого своя )) На этом предлагаю закончить дискуссию и не тратить на это время )) Всего доброго!


            1. fireSparrow
              21.03.2019 21:13

              Термин не может быть одновременно чётко определённым и в то же время значить для каждого что-то свое. Иначе это не термин.
              А то эдак мы и до альтернативной математики докатимся.
              Впрочем, раз вы хотите закончить дискуссию, то и вам всего доброго ;))