Инкапсуляция – это сокрытие или нет?

Эта тема мне далась очень сложно, потому что я не любитель всех этих точных определений и тем более не любитель дискутировать на эту тему. Очень часто сложно найти точное определение, поэтому я их просто не даю, а просто описываю вещи простым языком. И вот тут как раз очень часто люди придираются к моим словам, что я сказал что-то не точно и есть более точное определение. Еще раз повторю, что я против определений. 

Программирование меняется и многие вещи могут зависеть от языка. Тот же ООП может быть реализован по-разному. Разные авторы описывают инкапсуляцию по-разному, и кто из них более прав чем все остальные? Например, как инкапсуляцию определяет Grady Booch: "the process of compartmentalizing the elements of an abstraction that constitute its structure and behavior; encapsulation serves to separate the contractual interface of an abstraction and its implementation". Это самое правильное определение или кто-то хочет сказать, что Гради Буч ничего не понимает в объектно-ориентированном программировании? Пишите в комментариях, как неправ Гради.  

А мы посмотрим на современное то, что написано о инкапсуляции в Wikipedia. Я не знаю, где тут определение на странице, возможно я слепой, но можно ли говорить, что определение - это то предложение, которое начинается со слова Это (в английском is)? Лично я не уверен, потому что не все то определение, которое начинается с это. Но посмотрим, что вообще пишут в Вики:

Encapsulation, in object-oriented programming, is the bundling of data with the methods that operate on that data, or the restricting of direct access to some of an object's components. Encapsulation is used to hide the values or state of a structured data object inside a class, preventing unauthorized parties' direct access to them.

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

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

Попробую перевести это максимально точно: 

Инкапсуляция в объектно-ориентированном программировании - это объединение данных и методов для оперирования этими данными ИЛИ ограничение прямого доступа к каким-то компонентам объекта. Инкапсуляция ИСПОЛЬЗУЕТСЯ для того, чтобы прятать значения или состояния структурированных данных внутри класса, запрет неавторизованного прямого доступа к ним. 

Надеюсь, что мне удалось перевести это максимально точно. Это практически совпадает с определением, которое приводят в своем видео ExtremeCode:

https://www.youtube.com/watch?v=yNUJ3vAeyJQ

Единственная существенная разница между тем, что написано в Википедии и у них – между двумя частями стоит ИЛИ, а не И. Хотя чуть ниже в Вики будет написано, что на самом деле И/ИЛИ, но об это чуть-чуть дальше. 

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

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

Смотрим ту же википедию. Там есть целый раздел: Ограничение доступа против объединение данных с методами (Restricting access vs. bundling data with methods) и в нем в самом начале написано следующее: 

In object oriented programming languages, encapsulation refers to one of two related but distinct notions, and sometimes to the combination thereof:

•A language mechanism for restricting direct access to some of the object's components. 

•A language construct that facilitates the bundling of data with the methods (or other functions) operating on that data. 

Снова попробую перевести максимально точно, на сколько позволяет мой канадский:

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

- механизм языка для ограничения прямого доступа к каким-то компонентам объекта

- конструкция языка, которая позволяет объединять данные и методы (или другие функции) оперирующие над данными

В самом первом определении мы уже это слышали в более сжатом варианте и там это было объединено двумя английскими буквами OR (в русском это будет три буквы, и не те, которые пишут на заборе, а ИЛИ). Хотя эти три буквы уже не верны, правильнее было бы написать И/ИЛИ, потому что может быть как И, так и ИЛИ и об этом как раз говорит последний участок Вики, который я привел. 

В чем правы ExtremeCode – говорить о сокрытии – это не полный ответ и не полное определение инкапсуляции. Но в чем они не правы – это нормально говорить о том, что инкапсуляция – это сокрытие:

-  очень часто этому придается больше внимания просто потому, что эта тема более сложная. 

- это еще и зависит от языка. 

Снова возвращаемся к Вике: 

The second definition is motivated by the fact that in many OOP languages, components are not hidden automatically and this can be overridden; thus, information hiding is defined as a separate notion by those who prefer the second definition.

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

Я согласен с Вики, что первое определение имеет право на жизнь и для меня оно приоритетно, как для C# программиста. Просто в C# невозможно писать классы ни указав ни одного слова public. Нельзя просто отделить модификаторы доступа и забить на них болт, потому что тогда единственный способ использовать такие классы будет БДСМ кодинг. 

Да даже без C# я ему больше отдаю предпочтения, и я объясню почему. 

Есть языки программирования, в которых ООП реализован так, что у них нельзя просто так сразу же переопределять. 

Рассмотрим следующий пример: 

using System;

 

namespace IncapTest

{

    class Rectangle

    {

        int width;

        int height;

 

        public Rectangle(int width, int height)

        {

            this.width = width;

            this.height = height;

        }

 

        public int GetArea()

        {

            return width * height;

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("Hello World!");

            Rectangle r = new Rectangle(10, 10);

            r.GetArea();

        }

    }

}

Любые совпадения с кодом из упомянутого видео считать случайными. Но что произошло со свойствами width и height? Они автоматически скрыты в C#, мы не можем к ним получить доступ. Автоматом произошло сокрытие, потому что так работает C# и в этом языке сокрытие является основой инкапсуляции. Как только вы объединяете методы и данные в одну капсулу вы получаете модификаторы паравозом. 

А что будет со следующим примером: 

class CoolRectangle: Rectangle

{

    public CoolRectangle(int width, int height) :base(width, height)

    {

    }

 

    public int GetArea()

    {

    }

}

В C# такое делать нельзя, потому что GetArea автоматически скрыт и не может быть переопределен даже не смотря на то, что он публичный. 

Но что, если сделать все переменные публичными, а методы виртуальными, потеряем ли мы инкапсуляцию? Согласно второму пункту - нет, потому что мы все еще связали данные с методом. При изменении данных вызов метода возвращает новый результат. Хороший это будет подход к программированию? Оставлю этот вопрос без ответа. По крайней мере в отношении C#. 

Есть языки программирования, в которых нет такого понятия, как private. Python. У них нет инкапсуляции? Конечно есть, просто в таких языках инкапсуляция это чисто механизм языка, который позволяет объединить данные и методы, работающие с этими данными в единый класс. А выражения «и скрыть детали реализации от пользователя» как бы нет, если говорить о модификаторах доступа. Так что когда кто-то говорит, что инкапсуляция ничего не имеет общего с сокрытием – это абсолютно верно в отношении, языков, где нет сокрытия модификаторами доступа. Python. 

Вы скажете, что Питон не объектный язык? 

Можно устроить халивар и вспомнить JS, который тоже является ООП, хотя и не в классическом понимании этого слова, потому что там основой являются прототипы. 

В Objective-C до 2-й версии кажется тоже не было способа даже спрятать информацию, а ведь это язык со словом Objective в названии. Там реально механизм сокрытия это что-то с чем-то. 

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

Как я уже приводил пример из Вики выше, у них есть отдельный механизм Information hiding. 

In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed.

Снова понадеюсь на то, что канадский схож с английским и попробую перевести это:

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

Я переводил ни дословно, а старался передать именно смысл. В следующем абзаце как раз говориться о том, что information hiding использует как раз функции языка, такие как private.

Но забудем о Вики и попробуем ответить на вопрос - что является целью в ООП: 

1. Связать данные с методами в одном классе? 

2. Защитить данные от некорректного использования? 

Для меня это #2, потому что я живу в мире C#, поэтому я при разговоре о инкапсуляции всегда сделаю упор на сокрытие. 

Даже если забить на C# и говорить о Java, где все методы по умолчанию виртуальные (поправьте меня, если я не прав, но кажется это так, да и Java тут не единственный), я уделю все же первому пункту больше внимания просто потому, что для объяснения моим читателям второго пункта понадобился один пример, где методы и данные объединяются в одно целое и все публичное и виртуальное - приходи кто хош, меняй што хош. А вот для объяснения первого пункта даже целой главы не всегда достаточно. 

Снова вернемся к Вики и ее определению инкапсуляции – чему именно учит эта страница после того, как дали определение – связыванию или сокрытию? Чему учат в каждой первой книги, по крайней мере из тех, что я читал – связыванию или сокрытию? Если кто видел книгу, где учат связыванию, то напишите в комментариях, я обязательно прочитаю. Я пока не читал книг по Python, но в JS и Objective-C эту тему вообще опускают. 

Но тут есть еще очень важный пункт, который почему-то теряется в последнее время – инкапсуляция – это сокрытие реализации. Именно это сказано в видео ExtremeCode но я не знаю, что именно они имели ввиду, когда говорили это. 

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

Для меня инкапсуляция – это сокрытие реализации с помощью объединения (помещения в капсулу) методов и свойств. 

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

Посмотрим на следующий пример:

 

class File {

  public int Handle;

  public void Open(filename: string, access: int);

  public string ReadLine();

  public Write(line: string);

}

 

Можете поискать ошибки здесь, потому что этот код не корректный для C# языка, потому что. . . ну сами напишите в комментариях, нужно же оставить пищу для троллей. Я специально сделал все public, чтобы этот пример был одинаково полезным для языков с модификаторами доступа и без них. Для языка с модификатором private или protected мы скорей всего защитили бы переменную. Handle, но допустим, что у нас нет такой возможности. 

Это класс, который скрывает от нас, что такое Handle. Да, в данном примере она public, но нам и не нужно знать зачем нужна эта переменная, зачем она хранится и как она сипользуется, потому что это сокрытие ООП. 

Это как автомобиле. Есть двигатель. Мы знаем, что внутри есть поршни, где-то там есть масло, но для того, чтобы управлять автомобилем нам не нужно знать, как все это там реально работает. 

А теперь посмотрим на не ООП код: 

 

class File {

  public int Open(filename: string, access: int);

  public string ReadLine(int handle);

  public Write(int: handle, line: string);

}

 

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

Для меня модификаторы доступа – это всего лишь инструмент (механизм), с помощью которого мы еще и можем ограничить доступ к каким-то элементам и эти модификаторы доступа могут отсутствовать в языке. Сокрытие в виде модификаторов доступа – это не определение, это механизм языков, которые помогают делать капсулу безопасней, поэтому об этом и говорят в книгах по Java или C# и почти не говорят в Python или JS. 

Здесь я не хотел спорить с ExtremeCode с их определением, потому что я никаких определений пока не даю и надеюсь, они воспримут это правильно (если увидят). Опять же, я понимаю, почему они записали видео, потому что они считают, что теряется важный пункт в определении. А в случае с языками, где нет модификаторов доступа, но есть сокрытие реализации этот смысл действительно теряется, если под сокрытием понимать модификаторы доступа. 

Но в этом видео произошел парадокс – в самом видео как бы придираются к формулировке, но когда о их формулировке пишут что-то, то. . . в эфир летит мат. Я смотрю иногда их стримы и не раз слышал жесткую реакцию на комментарии. Ребята умные и их интересно слушать, если отбросить пошлость и грубость, поэтому у них есть от меня подписка и лайк под этим видео. 

Это тот случай, когда две точки зрения могут быть верными. Я бы даже сказал целых три точки зрения, потому что когда есть две точки зрения, между которыми стоит И/ИЛИ получается целых три верных варианта. Вот такой парадокс. 

Еще раз, я не пытался здесь придраться к чему-то, я просто хотел высказать свою точку зрения. Я вообще против этих всех четких формулировок, главное понимание, что такое ООП, зачем объединяются методы и свойства, зачем к ним ограничивается доступ. А название – инкапсуляция или инкастыляция и точное определение – это дело 10-е. 

У ExtremeCode где-то было сказано, что если на собеседовании спросят про инкапсуляцию, то нельзя говорить о том, что это сокрытие. Как я уже сказал, это говорить можно, но я бы бежал от такой компании, которая задаёт подобный вопрос на собеседовании, потому что для такой компании важнее определение, а не знание или понимание. В Канаде мне такой вопрос задавали только один раз на интервью и его проводил программист, родом с бывшего СССР (конкретную страну называть не буду, а то еще припишут мне что-нибудь). Я сразу понял, что там работать не буду и дальше интервью уже было формальностью, потому что я уже отвечал на вопросы лишь бы быстрее вежливо закончить разговор. 

В наше время вопрос о том, что такое инкапсуляция может стать таким же халиваром, как и пробелы против табов. 

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



Внимание!!! Если ты копируешь эту статью себе на сайт, то оставляй ссылку непосредственно на эту страницу. Спасибо за понимание

Комментарии

plonti

13 Мая 2022

Хорошая статья, спасибо. ExtremeCode — чисто провокатор, плюс видно, что не очень зрелый, молодой и горячий. Но, возможно это и хорошо. Потому что провоцирует отвечать на его вбросы людей обладающим большим опытом!


qurde

31 Марта 2023

Довольно интересно и это действительно довольно сложный вопрос 'Инкапсуляция', всеми недопонятая и бывает кажется, что и неправильная


Добавить Комментарий

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне