Объектно-ориентированное программирование (в дальнейшем ООП) — парадигма программирования, в которой основными концепциями являются понятия объектов и классов. ООП создано для моделирования алгоритмов, бизнес-процессов или любой иной формализованной логики. Проще говоря, ООП разработано для упрощения программирования комплексных программных продуктов. Далее попробуем разобраться с концепцией объектно-ориентированного программирования на простых примерах.
Содержание
Система объектно-ориентированного программирования (ООП) — это парадигма основанная на концепции «объектов», содержащих данные и методы.
Основной целью ООП является повышение гибкости и удобства сопровождения программ, это борьба с возрастающей сложностью современного ПО. При таком подходе сведения об объекте и его поведении (методы) находятся в одном месте, упрощая понимание того, как работает программа. Мы подробно рассмотрим каждую особенность ООП. Однако для начала разберемся, что такое объект.
Объект — любой предмет или сущность, имеющий состояние и поведение.
Состояние — это характеристики объекта, его параметры, поведение — осуществляемые им действия.
Пример:
Вот так реализация этого объекта будет выглядеть на объектно-ориентированном языке 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
На фоне роста спроса на ликвидность в бычьем рынке 2025 года, криптозаймы снова выходят на…
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…