Объектно-ориентированное программирование (в дальнейшем ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов. ООП создано для моделирования алгоритмов, бизнес-процессов или любой иной формализованной логики. Проще говоря, ООП разработано для упрощения программирования комплексных программных продуктов. Далее попробуем разобраться с концепцией объектно-ориентированного программирования на простых примерах.
Содержание
Система объектно-ориентированного программирования (ООП) — это парадигма основанная на концепции «объектов», содержащих данные и методы.
Основной целью ООП является повышение гибкости и удобства сопровождения программ, это борьба с возрастающей сложностью современного ПО. При таком подходе сведения об объекте и его поведении (методы) находятся в одном месте, упрощая понимание того, как работает программа. Мы подробно рассмотрим каждую особенность ООП. Однако для начала разберемся, что такое объект.
Объект — любой предмет или сущность, имеющий состояние и поведение.
Состояние — это характеристики объекта, его параметры, поведение — осуществляемые им действия.
Пример:
Вот так реализация этого объекта будет выглядеть на объектно-ориентированном языке Java:
class House { String address; String color; double are; void openDoor() { //здесь пишется код } void closeDoor() { //место для вашего кода } ... ... }
Различные состояния объекта представлены в виде переменных экземпляра, а поведение — это методы класса.
Помогут разобраться в этом вопросе курсы от наших друзей Mate Academy, Hillel и Powercode. Менторы смогут ответить на любые ваши вопросы.
Класс можно рассматривать как план, с помощью которого можно создать столько объектов, сколько захотите.
Возьмем класс Site
с двумя элементами данных
В следующем примере мы создали два объекта и предоставили им отдельные свойства с помощью конструктора:
(Продолжаем использовать Java)
public class Site { //поля (или переменные) String webName; int webAge; // конструктор Site(String name, int age){ this.webName = name; this.webAge = age; } public static void main(String args[]){ //создаем объекты Site obj1 = new Site("highload", 5); Site obj2 = new Site("yandex", 18); //Получаем данные объекта и выводим их в консоль System.out.println(obj1.webName+" "+obj1.webAge); System.out.println(obj2.webName+" "+obj2.webAge); } }
До ООП все языки программирования были процедурными. Назывались они так потому, что программист определял очень специфический набор процедур (подпрограмм), которые должен был выполнять компьютер. Это пошаговое руководство включало в себя прием данных, выполнение последовательности действий с этими данными, а затем вывод того, что получилось в результате этих действий.
Процедурные языки хорошо работали в те времена
Вот тут нам на помощь и приходит объектно-ориентированное программирование. Оно упрощает организацию данных и кода, делая их универсальными для разработки любых проектов.
Далее рассмотрим ООП более подробно и поговорим о четырех китах, на которых оно стоит.
При использовании чего-либо (предмета или метода) — вам не обязательно знать, как он работает. Для примера возьмем кофе-машину, внутри которой довольно сложный механизм. Однако все что нам от нее надо — нажав кнопку с изображением дымящейся кружки — получить порцию ароматного эспрессо.
То же самое верно и для объектов в ООП. В любом встроенном методе присутствует скрытый функционал. Например, в примере с объектом «Дом» есть метод openDoor()
. Он может состоять из нескольких элементов: поворота ключа в дверном замке, дергания за ручку и т.д. Но нам с вами не обязательно об этом знать. Все, что нужно, прописать этот метод в редакторе кода и она откроется. Это абстракция.
Инкапсуляция — это один из способов создания абстракции. Каждый объект представляет собой набор данных (переменные, методы).
Элементы внутри объекта обычно остаются закрытыми, что означает, что другие объекты и методы не могут получить к ним доступ — они инкапсулированы, заключены в оболочку. Роль оболочки обычно играют классы. При таком подходе программист может вносить изменения в структуру или содержимое объекта, не беспокоясь об общедоступном интерфейсе. На объекты можно воздействовать только с помощью их методов.
В дополнение к классам, объектно-ориентированные языки программирования также имеют подклассы. Они содержат все атрибуты родительского класса, но могут также содержать и другие атрибуты.
Для примера возьмем древнейшую игру — шахматы. У каждой шахматной фигуры есть свои классы с переменными и методами для передвижения и других действий. Более подробно рассмотрим пешку — обозначим ее классом Piece
, поместив для нее внутри необходимый функционал. Однако помимо стандартных функций, пешкам еще нужен метод, превращающий их в другие фигуры, по достижении конца доски. Мы назовем его методом transformPiece()
.
Мы не будем помещать его в класс, а вместо этого создадим подкласс под названием Pawn
. Поскольку это подкласс, он наследует все атрибуты от класса Piece
. Экземпляр подкласса Pawn
будет включать в себя не только метод transformPiece()
, но и базовые свойства и атрибуты класса-родителя (цвет, высоту, форму и разрешенное движение).
Вывод: Вместо того, чтобы создавать новые классы для всего, можно создать базовый класс, а затем расширить его новыми подклассами, там, где это необходимо. Создание подклассов экономит много времени, однако злоупотреблять их созданием не стоит, чтобы в них не запутаться.
Полиморфизм является результатом наследования. Полное понимание этой концепции требует некоторых знаний в области программирования, поэтому здесь мы будем придерживаться основ. Полиморфизм позволяет программистам использовать методы с одним и тем же именем, но с разными объектами.
Например, наш класс Piece может иметь метод move()
, перемещающий фигуру на одну позицию в любом направлении. Такая функция будет работать и для фигуры короля, но не для чего-либо еще. Чтобы решить эту проблему, мы можем определить новый метод move()
в подклассе Rook
, определяющий движение как неограниченное количество пробелов вперед, назад, влево или вправо.
Теперь, когда программист вызывает метод move()
и использует фигуру в качестве аргумента, программа будет точно знать, как она должна двигаться. Это экономит массу времени на попытки выяснить, какой из множества различных методов вы должны использовать. Это делает решение более общим и универсальным, расширяя базовую функциональность первоначального метода.
Основы ООП зародились еще в 60-х годах XX века. Норвежцы Кристен Найгаард и и Оле-Йохан Даль разработали язык для создания симуляций и назвали его Simula 67. Основной задачей языка была симуляция взрыва кораблей различного назначения и модификаций.
Проведя несколько опытов, ученые поняли, что гораздо удобнее делить корабли на группы по разным категориям. У каждой из них был свой собственный класс, генерирующий уникальное поведение и данные каждого отдельного экземпляра.
А вот сам термин «объектно-ориентированное программирование» впервые был произнесен вслух в компании Xerox, при разработке языка программирования Smalltalk. Ввели его, чтобы обозначить процесс применения объектов — как основу для вычислений. Вдохновленные проектом Simula 67, создатели Smalltalk сделали его динамичным.
В отличие от большинства статических систем того времени, с объектами можно было взаимодействовать на высоком уровне: изменять, создавать новые или удалять. Кроме того, Smalltalk был первым языком программирования, в котором была представлена концепция наследования.
Simula стал вдохновляющим примером для большинства других языков, в том числе Pascal и Lisp, в 1980-х годах к ним присоединился еще и C++ (который стал образцом реализации современного ООП).
Вот несколько популярных языков, поддерживающих принцип ООП:
Список, конечно же, неполный, на самом деле их гораздо больше.
Допустим, клиент заказал у вас сделать новый Тамагочи с белым медведем в качестве виртуального питомца. Вы принимаетесь за работу и создаете класс PolarBear
на JavaScript/TypeScript.
class PolarBear { private _weight: number = 990; constructor(weight: number = 0) { this._weight = weight } makeNoise() { console.log("ревет"); } eat() { console.log("ест все что захочет"); } sleep() { console.log("спит"); } roam() { console.log("бесцельно бродит); } }
Затем заказчик попросил вас впихнуть в разрабатываемый гаджет всех существующих медведей, чтобы белому было немного веселей. Вы, закатывая рукава, возвращаетесь к работе и создаете копии класса медведей. Следующее желание клиента — добавить информацию о происхождении для каждого питомца. Вы больше не дублируете код.
Теперь вы меняете сотни строк кода для всех восьми видов медведей. Все это сопровождается вашими недовольными возгласами и неминуемым появлением кучи ошибок из-за множества правок. Пока вы тренируетесь, ваш клиент снова звонит и просит добавить в игру грызунов и жирафа. Вы понимаете, что когда вы закончите, он захочет еще обезьян и гиппопотама и вам нужен лучший способ все это внедрить.
Чтобы приручить свой виртуальный зверинец, вам поможет ООП, а именно простая структуризация кода: черные медведи, гризли и медведи-ленивцы — объединим в класс Медведи. В то же время медведи, грызуны и обезьяны — будут помечены классом Животные. Вот так мы постепенно и построим наше генеалогическое древо.
Это только часть кода:
class Animal { private _weight: number; private _origin: string; constructor(weight: number = 0, origin: string = "") { this._weight = weight; this._origin = origin; } makeNoise(noise: string = "") { console.log("издал звук, похожий на: " + noise); } eat(food: string = "") { console.log("ест " + food); } sleep() { console.log("спит"); } roam() { console.log("бесцельно бродит"); } } class Bear extends Animal { constructor(weight: number, origin: string) { super(weight, origin); } makeNoise(noise: string = "рев") { super.makeNoise(noise); } eat(food: string = "все, что он хочет") { super.eat(food); } } class GrizzlyBear extends Bear { constructor(weight: number = 600, origin: string = "Северная Америка") { super(weight, origin); } } class Panda extends Bear { constructor(weight: number = 230, origin: string = "Китай") { super(weight, origin); } makeNoise() { super.makeNoise("писк"); } eat() { super.eat("молодые побеги бамбука"); } }
Надеюсь, сам принцип понятен. А от теории, как известно, до реальной практики всего один шаг.
В конце, как обычно, несколько релевантных ссылок на актуальные видеоролики по теме:
https://m.youtube.com/watch?v=M58eiYbM6AE
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…