Существует большое непонимание того, что такое объектно-ориентированное программирование на самом деле и его истоки. Термин «объект» впервые был придуман в 1950-х годах и стал действительно популярным в начале 60-х годов в кругах Лиспа как мощный шаблон проектирования. Наконец, в 70-х годах Алан Кей разработал первый объектно-ориентированный язык Smalltalk.

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

Что такое сообщение?

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

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

Наша проблема…

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

Приведенный выше код работает отлично, но, поскольку мы работаем с массивом в качестве параметра, он не звучит очень семантично. Неясно, принадлежит ли список оценок одному ученику. Как это исправить? Что ж ... Есть два решения этой проблемы:

  1. Мы меняем имя функции на getStudentBestGrade
  2. Мы передаем в качестве параметра ученика как объект.

Конечно, остановимся на втором! ура!

Использование ключевого слова class

Что ж, поскольку мы любители объектно-ориентированного программирования, мы можем сделать это с помощью ключевого слова class. В любом случае, это такая простая работа:

Теперь код выглядит намного лучше, так как я могу просто передать ученика в качестве параметра и: Бинго! Намного лучше, чем в предыдущей версии

Но идея данной статьи не в этом. Выглядит неплохо, но для этого мы используем объектно-ориентированную нотацию JavaScript. Почему бы не сделать это только с функциями? Так что продолжайте читать :)

Наш первый функциональный объект

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

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

Хорошо, но что, черт возьми, за состояние? Думайте о состоянии как о чем угодно, что может заставить ваши функции выводить разные значения для одного и того же ввода, в этом случае параметр initial делает именно это.

Как мы видим в приведенном выше примере, для одних и тех же счетчиков каждый раз, когда мы вызываем функцию, на выходе получаем другое значение. В качестве обзора обратите внимание, что функция Counter в примере создает две функции с частным встроенным значением внутри. Разве это не то, что делают частные атрибуты объектов? ;)

Теперь, когда мы понимаем внедрение состояний, мы можем немного усложнить ситуацию и написать класс только для JavaScript, используя только функции. Почему только JavaScript? Потому что мы будем использовать JSON (JavaScript Object Notation).

Как видим, мы использовали тот же подход, что и на примере счетчика. Наша функция student (представляющая наш класс) получает оценки в качестве параметра и поддерживает его как частный атрибут _grades. Открытые методы (getGrades, getBestGrade) этого класса возвращаются в виде JSON. Поскольку этот класс написан с использованием красивой функции, нет необходимости использовать ключевое слово new.

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

Надеюсь, вам это понравится, именно сейчас начинается самое интересное! ❤

Обозначение объекта передачи сообщения

Напишем тот же объект, что и раньше, но используя стратегию передачи сообщений.

Как мы видим, эта реализация ООП на первый взгляд выглядит не очень элегантно в JavaScript, но я могу гарантировать, что она будет работать на большинстве популярных языков программирования. Идея не в том, что эта реализация может делать по-другому, а в том, как мы можем расширить это и реализовать настоящую классную иерархию и полиморфизм (мы сделаем это после следующего заголовка).

Чтобы использовать стратегию передачи сообщений, вы должны понимать, что для каждого сообщения объект будет иметь разные обработчики (функции), которые будут специализироваться на работе с сообщением. Если мы не передаем никаких параметров, мы можем просто получить функцию и использовать ее более гибко. Ниже я покажу вам, как можно использовать стратегию передачи сообщений:

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

Наследование и полиморфизм

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

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

  1. Студенты должны иметь имя и возраст. Итак, на данный момент конструктор также должен иметь имя и возраст.
  2. Одним из атрибутов нашего класса будет базовый класс, который будет построен с параметрами, отправленными в конструктор Student.
  3. Если сообщение, которое мы ищем, не найдено, мы перенаправим его в базовый класс в случае по умолчанию переключателя.

Поехали, дамы и господа! : D

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

Заключение

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

использованная литература

[1] ООП против FP - https://kara.codes/til/referential-transparency