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

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

Очень красивое слово – инкапсуляция. Честно сказать, я не очень люблю красивые слова, по которым сложно понять, что именно они означают. И несмотря на то, что на первых порах вы не очень много внимания будете уделять структуре и качеству объектов, я постараюсь убедить вас в том, что эта тема очень важна.

Инкапсуляция – это свойство, благодаря которому разработчику, использующему определенный строительный блок (код), не нужно знать, как он на самом деле реализован и работает для корректного использования этого строительного блока. Что это значит? Когда вы садитесь за руль автомобиля, вы знаете, как устроен его двигатель или коробка передач? Лично я понятия не имею. Нет, я в курсе, что двигатель ворочает коробку передач, а та передает свои усилия на колеса, и этого мне вполне достаточно, чтобы повернуть ключ, воткнуть первую передачу и начать движение. Программисту, использующему ваш класс, не обязательно знать, как он реализует необходимые возможности. Я бы сказал больше, ему абсолютно не нужно даже знать ничего лишнего. Разрабатывая класс, вы должны проектировать его таким образом, чтобы все методы и свойства, выполняющие основную работу, были закрыты.

Разрабатывая классы, вы можете объявлять его методы и свойства с различными правами доступа. Забегая вперед, скажу, что их немного: public, private, protected и published. Что имеется в виду под доступом? Открытые методы и классы видны другим классам.

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

Сразу же дам совет – никогда не делайте открытыми переменные класса. Они должны быть закрыты, а если нужно иметь возможность воздействия на переменные, то для этого лучше использовать методы или свойства (property). То есть, для чтения и для изменения переменной должны использоваться только методы, без возможности прямого воздействия.

Скрытие деталей реализации называется инкапсуляцией (от слова «капсула»). Ничего сложного в этом понятии нет: ведь и в обычной жизни мы пользуемся объектами через их интерфейсы. Сколько информации пришлось бы держать в голове, если бы для просмотра новостей надо было знать устройство телевизора!

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

Сказанное выше можно сформулировать более кратко и строго: объект — это инкапсулированная абстракция с четко определенным интерфейсом.

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

Наследование

Одно из величайших достижений в ООП — наследование. Рассмотрим пример. Вы написали объект – «гараж». Теперь вам нужно написать объект «дом». Гараж — это, грубо говоря, однокомнатный дом. Оба эти здания обладают одинаковыми свойствами — стены, пол, потолок и т. д. Поэтому желательно взять за основу гараж и доделать его до дома. Для этого вы создаете новый объект «Дом» и пишете, что он происходит от «Гаража». Ваш новый объект сразу примет все свойства гаража. Это значит, что уже есть стены, пол и потолок, и остается добавить только окна и интерьер. Теперь у вас будет уже два объекта: гараж и дом. Используя данный прием, можно, например, создать еще будку для собаки. Для этого снова создается объект «Будка», который происходит от «Гаража» (можете произвести построение от «Дома», чтобы в будке у собаки был интерьер, но это мне кажется лишним, собака этого просто не оценит). Нужно только уменьшить размер гаража, изменить вход, и он превратится в будку. В итоге получается древовидная иерархия наследования свойств объектов, которая показана на рисунке:

Пример наследования

Тут еще нужно запомнить два понятия: предок и потомок. Предок — класс, от которого происходят другие классы. Потомок — класс, который происходит или порожден из другого. Например, гараж — это предок для дома, будки и дачи. Дом, будка и дача — потомки от гаража. Один объект может быть и потомком, и предком одновременно. Например, объект дом является потомком гаража и предком, например, для многоэтажки.

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

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

Полиморфизм

Есть еще одна возможность, которая очень удобна в ООП, — полиморфизм. Что это такое? Представим, что у гаража дверь открывается вверх, а у дома должна открываться в сторону. Дом происходит от гаража, поэтому у него дверь будет открываться тоже вверх. Как же тогда быть? Вы просто должны изменить (переписать) у дома процедуру, отвечающую за открытие двери. Тогда дом получит все свойства гаража, но при открывании двери подставит свою процедуру. Что-то подобное и есть полиморфизм. Другими словами, это когда объекты разных иерархий по-разному реагируют на одно и тоже событие.

Для того чтобы можно было изменить процедуру, отвечающую за открывание двери, она должна быть объявлена у гаража как «виртуальная» (virtual). Виртуальная процедура говорит о том, что в порожденном объекте она может быть заменена.

Есть еще одно слово, которое может указать на необходимость полиморфизма, — dynamic. В принципе, результат будет идентичен использованию virtual, разница только в том, что virtual оптимизирован для повышения скорости программы, a dynamic будет выполняться медленнее, но зато код результата будет меньше.

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

Процедура, отвечающая за создание стен у гаража:

  • Начало
  • Создать стены
  • Конец

Процедура, отвечающая за создание стен у дома:

  • Начало
  • Вызвать объект предка.
  • Повесить на стены картины.
  • Конец

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

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

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

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

Ваш адрес email не будет опубликован.