Сообщество Engee

Объектно-ориентированное программирование (ООП)

Автор
avatar-yurevyurev
Notebook

Объектно-ориентированное программирование в Engee: структуры и методы

Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на концепции "объектов", которые могут содержать данные (в виде полей или атрибутов) и код (в виде методов). Основные принципы ООП включают:

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

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

  • Пользовательские типы (структуры)
  • Множественную диспетчеризацию (более мощная альтернатива методам классов)
  • Композицию (вместо наследования)

В Engee подход отличается от традиционного ООП в таких языках, как Python или Java, но позволяет достигать аналогичных результатов более гибкими способами.

ООП-стиль в Engee особенно полезен:

  • При работе с сложными структурами данных
  • Когда нужно моделировать предметную область с четкими сущностями
  • Для организации кода в больших проектах
  • Когда требуется полиморфное поведение функций

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

Анализ примера кода

Давайте разберем представленный пример, который демонстрирует базовые возможности ООП в Engee:

In [ ]:
struct Person # Определяем тип (аналог класса)
    name::String
    age::Int
end

Здесь мы создаем структуру Person с двумя полями: name (строка) и age (целое число). В терминах ООП это аналогично созданию класса с атрибутами.

In [ ]:
function greet(person::Person) # Метод для типа Person (аналог метода класса)
    println("Привет, меня зовут $(person.name), мне $(person.age) лет!")
end
Out[0]:
greet (generic function with 1 method)

Это функция, специализированная для работы с типом Person. В Engee методы не "принадлежат" объектам, как в классическом ООП, но благодаря множественной диспетчеризации мы можем создавать специализированные версии функций для разных типов.

In [ ]:
function test_person()
    person = Person("Анна", 25)
    
    @assert person.name == "Анна"
    @assert person.age == 25
    
    println("Тест метода greet():")
    greet(person)
    
    println("Тест пройден успешно!")
end
Out[0]:
test_person (generic function with 1 method)

В тестовой функции мы создаем экземпляр структуры Person, проверяем его поля и вызываем метод greet.

Расширенный пример: система управления сотрудниками

Давайте расширим пример до более практического применения. Данный код представляет собой реализацию простой системы управления сотрудниками компании с использованием объектно-ориентированного подхода в Engee. В основе системы лежат два пользовательских типа: Employee (сотрудник) и Manager (менеджер). Тип Employee содержит базовые поля: идентификатор (id), имя (name), отдел (department) и зарплату (salary). Тип Manager использует композицию, включая в себя объект Employee и добавляя специфичные для менеджера поля — размер команды (team_size) и бонус (bonus).

Код демонстрирует ключевые принципы ООП через несколько специализированных функций. Функция annual_salary имеет две реализации — для обычного сотрудника (просто умножает месячную зарплату на 12) и для менеджера (добавляет бонус к годовой зарплате). Функция print_info также перегружена для разных типов сотрудников, обеспечивая полиморфное поведение — вывод разной информации в зависимости от типа объекта. Функция give_raise! изменяет зарплату сотрудника на указанный процент, демонстрируя работу с изменяемыми данными (восклицательный знак в имени функции — соглашение Engee для функций с побочными эффектами).

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

In [ ]:
mutable struct Employee
    id::Int
    name::String
    department::String
    salary::Float64
end
struct Manager
    employee::Employee 
    team_size::Int
    bonus::Float64
end
function annual_salary(emp::Employee)
    emp.salary * 12
end
function annual_salary(mgr::Manager)
    (mgr.employee.salary * 12) + mgr.bonus
end
function print_info(emp::Employee)
    println("""
    Сотрудник: $(emp.name)
    ID: $(emp.id)
    Отдел: $(emp.department)
    Месячная зарплата: $(emp.salary)
    Годовая зарплата: $(annual_salary(emp))
    """)
end
function print_info(mgr::Manager)
    println("""
    Менеджер: $(mgr.employee.name)
    ID: $(mgr.employee.id)
    Отдел: $(mgr.employee.department)
    Размер команды: $(mgr.team_size)
    Месячная зарплата: $(mgr.employee.salary)
    Бонус: $(mgr.bonus)
    Годовая зарплата: $(annual_salary(mgr))
    """)
end
function give_raise!(emp::Employee, percent::Float64)
    emp.salary *= (1 + percent/100)
    println("Зарплата $(emp.name) повышена на $percent%")
end
In [ ]:
# Создаем обычного сотрудника
emp1 = Employee(101, "Иван Петров", "IT", 1500.0)
# Создаем менеджера (который содержит сотрудника)
mgr1 = Manager(Employee(201, "Анна Сидорова", "IT", 2500.0), 5, 5000.0)
# Выводим информацию
println("\nИнформация о сотруднике:")
print_info(emp1)
println("\nИнформация о менеджере:")
print_info(mgr1)
# Повышаем зарплату
give_raise!(emp1, 10.0)
give_raise!(mgr1.employee, 8.0)  # Обращаемся к вложенному сотруднику
# Проверяем новые зарплаты
println("\nПосле повышения:")
print_info(emp1)
print_info(mgr1)
println("\nТест завершен успешно!")
Информация о сотруднике:
Сотрудник: Иван Петров
ID: 101
Отдел: IT
Месячная зарплата: 1500.0
Годовая зарплата: 18000.0


Информация о менеджере:
Менеджер: Анна Сидорова
ID: 201
Отдел: IT
Размер команды: 5
Месячная зарплата: 2500.0
Бонус: 5000.0
Годовая зарплата: 35000.0

Зарплата Иван Петров повышена на 10.0%
Зарплата Анна Сидорова повышена на 8.0%

После повышения:
Сотрудник: Иван Петров
ID: 101
Отдел: IT
Месячная зарплата: 1650.0000000000002
Годовая зарплата: 19800.000000000004

Менеджер: Анна Сидорова
ID: 201
Отдел: IT
Размер команды: 5
Месячная зарплата: 2700.0
Бонус: 5000.0
Годовая зарплата: 37400.0


Тест завершен успешно!

Выводы

Подводя итоги стоит ещё раз разобраться с тем какие аналоги и возможности функционального программирования в Engee мы можем использовать для реализации объектно ориентированного подхода.

Ключевые концепции ООП в Engee

  1. Структуры вместо классов: В Engee используются структуры (struct) для создания пользовательских типов, которые могут содержать данные, но не могут содержать методы (функции определяются отдельно).

  2. Множественная диспетчеризация: В отличие от традиционного ООП, где методы "принадлежат" объектам, в Engee функции определяются независимо, а конкретная реализация выбирается на основе типов всех аргументов.

  3. Композиция вместо наследования: Engee не поддерживает классическое наследование. Вместо этого рекомендуется использовать композицию (включение одного объекта в другой), как показано в примере с Manager, содержащим Employee.

  4. Инкапсуляция: По умолчанию все поля структуры в Engee являются публичными. Для инкапсуляции можно использовать модули или соглашения об именовании (например, начинать приватные поля с подчеркивания).

  5. Полиморфизм: Реализуется через множественную диспетчеризацию — разные методы одной функции могут быть вызваны в зависимости от типов аргументов.

Преимущества подхода Engee к ООП

  1. Гибкость: Множественная диспетчеризация более мощная, чем классическое ООП, так как позволяет выбирать реализацию метода на основе всех аргументов, а не только первого (как в Python или Java).

  2. Производительность: Система типов Engee и компилятор оптимизированы для работы со структурами, что обеспечивает высокую производительность.

  3. Ясность кода: Разделение данных (структуры) и поведения (методы) может сделать код более понятным и легким для поддержки.