Объектно-ориентированное программирование: инкапсуляция, полиморфизм, наследование
Объектно-ориентированное программирование - это парадигма программирования, основанная на определении объектов, которые отправляют друг другу сообщения. Эти объекты также содержат собственные общедоступные и внутренние интерфейсы , о которых я расскажу позже в этой статье.
Чтобы успешно реализовать объектно-ориентированный дизайн, нужно тщательно и интуитивно проектировать вокруг 4 основных столпов, известных как 4 столпа объектно-ориентированного дизайна:
- Абстракция
- Наследование
- Инкапсуляция
- Полиморфизм
Абстракция:
Абстракция и инкапсуляция - очень похожие объектно-ориентированные концепции, но отличаются в нескольких ключевых областях. Абстракция позволяет инженерам мыслить на более высоком уровне, получая "взгляд с высоты птичьего полета" на программу, не увязая в лежащих в основе механиках. Эта перспектива «более высокого уровня» называется уровнем разработки. В отличие от инкапсуляции, абстракция имеет тенденцию обобщать вещи, скрывая нежелательные данные и выявляя необходимые данные. С другой стороны, инкапсуляция фокусируется на внутренних механизмах действия программы и сокрытии этих механизмов (состояний / поведения) с помощью модификаторов доступа.
Пример использования абстракции - в языках программирования. Первоначально Launch School использовала Ruby, потому что он был предназначен для англоговорящего человека, а не для компьютера. Написание на Ruby больше похоже на письмо на английском, и многие лежащие в его основе механизмы скрыты. Это достигается благодаря высокому уровню абстракции в Ruby. Языки нижнего уровня не содержат большой абстракции, поэтому от программиста требуется учитывать большее количество базовых атрибутов уровня реализации, чтобы код работал.
Design-Level: High-level, 'birds eye' view of a program. The realm of abstraction, responsible for getting rid of unnecessary data that doesn't relate to the overall design of a program. Implementation-Level: Mechanics-layer. The data, states, and behavior that contribute to the functionality of a program. The realm of encapsulation that shields unnecessary data to the public interface.
Наследование:
В зависимости от языка программирования существует множество различных типов наследования. Ruby, однако, допускает только единичное наследование между классами и использует то, что называется миксинами, когда подклассы к .
Single Inheritance: Sub-class/child class inherits from one super class.
Пример одиночного наследования в Ruby:
В приведенном выше коде класс Dog
наследует поведение класса Animal, и любой объект, созданный из Dog
, может вызывать методы в Animal
. В этом случае для объектов, созданных из Dog
класса, вызывается метод конструктора из Animal
.
Наследование в Ruby помогает извлекать общее поведение из нескольких классов и перемещать их в один суперкласс. Наследование также считается абстракцией, потому что мы удаляем повторяющийся код и помещаем его в обобщенную единицу, которая делает программу более понятной в отношении того, что она делает, и целей, стоящих за определенным поведением.
Инкапсуляция:
Другой фрейм для просмотра инкапсуляции - это «объединение». Инкапсуляция принимает разные классы, методы и переменные и объединяет их в единый блок для справки.
Такое объединение может помочь снизить когнитивную нагрузку на программиста, добавив еще один уровень абстракции. Инкапсуляция также может скрыть состояния и поведение от прямого доступа, поэтому программисты не смогут случайно изменить состояния и поведения.
Инкапсуляция встречается во многих нишах Ruby, некоторые примеры находятся в:
- Переменные
- Методы
- Классы
Переменные, в частности переменные экземпляра, можно инкапсулировать с помощью ключевых слов private
и protected
. Ключевое слово private
скрывает данные из открытого интерфейса метода, что делает невозможным прямой доступ к ним извне класса. Ниже приведен пример инкапсуляции ключевым словом private
в действии:
Пример инкапсуляции:
В приведенном выше коде создается единый блок, содержащий методы: класс Dog
. После определения класса необходимо определить открытый интерфейс модуля. Метод конструктора initialize
в строке 2 и метод экземпляра to_s
в строке 6–8 являются частью открытого интерфейса класса Dog
.
Public Interface:
All the states and method’s available for direct-access outside of the Dog
class. It is the 'logical point which outside classes, objects, and methods interact.'
Оба класса initialize
и to_s
доступны извне. Однако метод получения name
, определенный для строки 12, скрыт извне класса по ключевому слову private
. Это заключительный этап инкапсуляции, ограничивающий доступ к ненужным общедоступным данным внутри модуля.
При вызове метода получения name
извнеDog
запускается NoMethodError
, поскольку в этой области недоступен метод. Кроме того, переменная экземпляра name
скрыта извне класса, поэтому единственный способ получить доступ к имени собаки - использовать метод to_s
.
Инкапсуляция с использованием ключевого слова protected
аналогична private
, за исключением того, что ключевое слово public
позволяет осуществлять межклассовое взаимодействие между состояниями и поведениями, определенными под ним. Это полезно, когда вам нужны два класса для обмена информацией, но вы не хотите, чтобы эта информация ни в одном из общедоступных интерфейсов класса.
Инкапсуляция происходит во многих ключевых игроках Ruby. Например,
- Классы: инкапсулируйте методы.
- Методы: инкапсулируйте логику.
- Объекты: инкапсулируют состояние и поведение.
Полиморфизм:
Короче говоря, полиморфизм - это способность данных быть представленными более чем одним способом. Рубисты обычно реализуют полиморфизм с помощью двух процессов:
- Через наследование.
- С помощью утиного ввода.
Полиморфизм через наследование:
До сих пор мы обсуждали концепцию одиночного наследования в Ruby. Однако есть еще одна форма наследования, которую использует ruby: наследование интерфейса. Наследование интерфейса использует mixins
для включения модулей в класс, при этом каждый класс наследуется от интерфейса, предоставленного модулем.
Полиморфизм посредством утиного ввода:
Утиная печать основана на поговорке: «Если она ходит как утка и ведет себя как утка, значит, это должна быть утка». Основное внимание уделяется тому, что объект может делать, а не тому, что он равно. Согласно утиной типизации, нужно обрабатывать объекты в соответствии с определенными методами / поведением, а не унаследованными классами и смешанными модулями.
Пример утиного ввода:
В приведенном выше коде все 4 класса: Cat
, Dog
, Bird
и Fish
будут пытаться вызвать метод экземпляра make_noise
. Однако в последнем элементе массива, объекте класса Fish
, нет поведения для создания шума (рыба не издает шум). Таким образом возникает ошибка и происходит сбой кода.
Вместо того, чтобы создавать суперклассы для каждого из классов, мы явно определяем методы внутри каждого класса без использования наследования. Эта система типов предназначена в первую очередь для программистов, которых больше заботит удобство, а не безопасность типов. Это одна из форм полиморфного поведения из-за того, что вызов метода make_noise
генерирует разные результаты или вообще ничего не дает, в зависимости от класса объекта.
Резюме:
Знание и практика четырех столпов объектно-ориентированного проектирования имеют решающее значение для развития высокого мастерства в разработке программного обеспечения. Освоение этих концепций позволяет программным системам стать более гибкими, адаптируемыми и понятными. Эти принципы применимы не только к Ruby, но и охватывают множество различных языков программирования, поскольку большинство языков поддерживают объектно-ориентированную парадигму.
Большое спасибо Карлу Лингия за поддержку и руководство в изучении этих столпов, а также за контент, представленный в этой статье, особенно в отношении основ инкапсуляции и абстракции.
Еще раз благодарим дружелюбный и услужливый персонал Launch School за то, что помог мне начать мои первые шаги на долгом пути от новичка до мастера.