Перейти к контенту

Прозекторская


Рекомендуемые сообщения

почему эти три системы (все три) друг на друге строятся

Ну они конечно иерархически подчинены. Самая независимая - система событий (сигналов, ивентов и т.п.). Система хранения уже зависит от событий, поскольку использует события для инициализации себя в нужные моменты. Таймеры зависимы и от событий (в основном от апдейтов) и от системы хранения (если сохраняемые). Мои таймеры тесно используют особенности моей системы событий. Песочницу от xStream таким же образом будет использовать тяжеловато. Соответственно, компоненты xStream связаны примерно таким же образом и так же неотделимы друг от друга.

 

"Для чего нужно ООП?" - вот понятия не имею.

 

Сперва, а что вообще ООП? Классически считается, что ООП - это три таких идеи: инкапсуляция, наследование, полиморфизм. Попробую показать на примере своих таймеров. Инкапсуляция - это объединение в одном флаконе состояния и действий (или иными словами данных и операций над этими данными). Вот есть задача выполнить некое действие в некий отдалённый момент, не сейчас. Для этого по идее можно вызвать функцию, и наработаны способы вызвать её "не сейчас, а потом". Но в придачу к вызову функции надо ещё и донести до этого вызова некие данные, с которыми надо что-то в тот момент сделать. Конечно и это можно сделать подручными средствами, но ООП предоставляет готовый механизм - инкапсуляцию данных и кода в одну сущность - объект. Это оформляется немного по разному в разных языках, но ноги растут из древней struct языка СИ, или record языка паскаль, или используются универсальные таблицы, как в Lua. Короче, такая штука с полями-данными и полями-функциями. Это удобно, позволяет ограничить область видимости данных, более структурно оформить код и ещё много чего по мелочи. Обычно во всех языках традиционно используется неявный первый аргумент (this, self и т.п.) функций-членов, чтобы связать данные и операции над этими данными.

Получился такой класс (это несохраняемый таймер, пример с упрощениями):

class "quick_timer"
function quick_timer:__init() -- конструктор таймера
end
function quick_timer:start(priority) -- Запуск таймера
end
function quick_timer:condition() -- условие
end
function quick_timer:action() -- действие
end

Я не затрагиваю здесь реализацию, только интерфейс. Методов там гораздо больше, чем показано. Конструктор срабатывает при создании объекта класса, метод start - запускает. Запуск таймера с одновременным созданием экземпляра класса будет выглядеть так:

quick_timer(time):start(true)

 

Роли остальных методов такие:

condition - метод, который проверяет некое условие, какое там задам. Когда метод возвращает true, таймер заканчивает свою работу и вызывает метод action, который делает то, что там напишу.

 

Теперь наследование и полиморфизм. Я выше запихал в один флакон мои данные и функции, но неясно, а что это мне дало. Сейчас объясню. То, что приведено выше, - базовый класс таймера, который только обеспечивает функционал собственно таймера. Хотя это и приличный объём кода, однако вместо общего условия и действия там стоят заглушки, т.е. методы condition и action - пустые. Чтобы сделать что-то полезное, мне надо создать новый класс на основе этого и там переопределить эти методы (т.е. собственно задать условие срабатывания и действие по срабатыванию). Пример, таймер, который ждёт выхода в онлайн какого-либо объекта:

class "wait_object_online" (ogse_qt.quick_timer)
function wait_object_online:__init(id) -- аргумент - id объекта, за которым следим
   self.obj_id = id -- запомнили объект, за которым следим
end
function wait_object_online:condition() -- наше кастомное условие
      return level.object_by_id(self.obj_id) -- сработает по появлению клиентского объекта
end
function wait_object_online:action() -- наше кастомное действие
   -- здесь что-то делаем по факту выхода объекта в онлайн
end

-- Использование:

wait_object_online(some_id):start(false)

 

сразу об аргументе метода start. Это приоритет таймера.

false - проверки с низким приоритетом, все выстраиваются в одну очередь и проверяется по одной за очередной апдейт актора.

true - проверяется на каждом апдейте актора.

В данном случае решили, что задержка срабатывания не критична.

 

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

 

Здесь и видим в действии идею наследования и полиморфизма. Мы унаследовали новый таймер от старого, при этом весь его функционал перешёл в новый класс. А то, что надо - заменили на свои методы, т.е. переопределили иными словами. Полиморфизм же заключается в том, что имеющийся там код базового класса "не замечает", что функции condition и action - новые и вызывает их как свои.

 

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

 

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

Гради Буч - Объектно-ориентированный анализ и проектирование с примерами приложений

 

 

  • Спасибо 1
  • Полезно 2
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Поделиться этим сообщением


Ссылка на сообщение

 

 

использую оригинальный пысовский метод level.add_call()

Это не ООП, а типичный процедурный подход, поскольку отсутствует инкапсуляция кода и данных. Ответь на простой вопрос, как ты при этом будешь хранить данные, которые надо "донести" от места/момента запуска до места/момента срабатывания? В принципе конечно можно использовать замыкания, но как по мне - это эрзац и вообще не ООП, а элемент функционального программирования.

 

 

 

Получается, что приведенные методы (ну кроме конструктора), должны быть виртуальными

Если вкратце, то в Lua, в силу прототипного ООП, все методы заведомо виртуальные, поскольку определяются ссылками, хранящимися прямо в таблице/юзердате (что аналогично таблице виртуальных методов C++).

 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Поделиться этим сообщением


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

я так понял, что ты сделал некую обёртку для level.add_call(), позволяющую хранить данные до вызова функции?

 

Я то как раз сделал наоборот. Специально для "процедурщиков" написал обёртку над классом таймера, чтобы запускать в процедурно-ориентированном стиле. Правда только для сохраняемых таймеров. В итоге, можно и так сделать

ogse_st_mgr.start_timer(timer_name, <задержка>, <имя функции>, <аргументы>)

Но это естественно сильно ограничивает поле применения. Аргументы не могут быть любого типа, срабатывает только по задержке. Хотя конечно написать ещё одну обёртку с дополнительной функцией-условием тоже можно, но как по мне - это уже извраты и лучше использовать собственно класс таймера.

Изменено пользователем malandrinus
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

Поделиться этим сообщением


Ссылка на сообщение
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...