Malandrinus 615 Опубликовано 28 Января 2015 почему эти три системы (все три) друг на друге строятся Ну они конечно иерархически подчинены. Самая независимая - система событий (сигналов, ивентов и т.п.). Система хранения уже зависит от событий, поскольку использует события для инициализации себя в нужные моменты. Таймеры зависимы и от событий (в основном от апдейтов) и от системы хранения (если сохраняемые). Мои таймеры тесно используют особенности моей системы событий. Песочницу от 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 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 28 Января 2015 использую оригинальный пысовский метод level.add_call() Это не ООП, а типичный процедурный подход, поскольку отсутствует инкапсуляция кода и данных. Ответь на простой вопрос, как ты при этом будешь хранить данные, которые надо "донести" от места/момента запуска до места/момента срабатывания? В принципе конечно можно использовать замыкания, но как по мне - это эрзац и вообще не ООП, а элемент функционального программирования. Получается, что приведенные методы (ну кроме конструктора), должны быть виртуальными Если вкратце, то в Lua, в силу прототипного ООП, все методы заведомо виртуальные, поскольку определяются ссылками, хранящимися прямо в таблице/юзердате (что аналогично таблице виртуальных методов C++). Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение
Malandrinus 615 Опубликовано 28 Января 2015 (изменено) из входных параметров только: имя таймера, время (таймаут), функция, которая будет вызвана по окончанию таймера и аргументы, переданные в эту функцию. я так понял, что ты сделал некую обёртку для level.add_call(), позволяющую хранить данные до вызова функции? Я то как раз сделал наоборот. Специально для "процедурщиков" написал обёртку над классом таймера, чтобы запускать в процедурно-ориентированном стиле. Правда только для сохраняемых таймеров. В итоге, можно и так сделать ogse_st_mgr.start_timer(timer_name, <задержка>, <имя функции>, <аргументы>) Но это естественно сильно ограничивает поле применения. Аргументы не могут быть любого типа, срабатывает только по задержке. Хотя конечно написать ещё одну обёртку с дополнительной функцией-условием тоже можно, но как по мне - это уже извраты и лучше использовать собственно класс таймера. Изменено 28 Января 2015 пользователем malandrinus Плагины Total Commander для работы с игровыми архивами: Архиваторный плагин (для работы с одиночным архивом): link1 link2 Системный плагин (для распаковки установленной игры): link1 link2 Поделиться этим сообщением Ссылка на сообщение