Всем привет!
Сегодня я расскажу о применении объектно-ориентированного программирования (ООП) на LUA. Ранее, я показывал, как можно его обойти. И, в целом, считаю, что, если без него можно обойтись, то нужно обходиться без него.
Но, к сожалению, не всегда без него удобно обходиться. Я в своих скриптах столкнулся с необходимостью сильного вложения данных. То есть, есть массив с перечнем бумаг, есть массив с записью всех свечей, в нем по каждой свече есть таблица с данными свечей, а среди них есть таблица времени. В общем, ужас какой-то. И не самое страшное написать так работающий код. Это половина дела. Если же через какое-то время встанет необходимость корректировать код, то там будет сложно разобраться.
Ну, ладно, надеюсь, что я вас убедил, что иногда применение ООП необходимо.
Материалы, на основе которых я постигал ООП в LUA:
1. Книга автора языка программирования Роберту Иерузалимски «Программирование на языке LUA» (но в книге достаточно сложно изложен данный вопрос);
2. Видео-ролик на youtube «Костыльный ООП (Объектно Ориентированное Программирование в Lua)» - https://www.youtube.com/watch?v=Sw7mpDUoRo0&t=718s. Тут достаточно хорошо все показано и рассказано.
Что же такое это ООП?
Есть простейшие типы данных. В том числе числа, строковые данные. В ООП основные операции идут с более сложным типом данных – с объектами. В свою очередь, объект представляет из себя некую сущность внутри которой есть переменные, которые называются свойствами и функции, которые называются методами.
Зачастую при объяснении ООП используют различные примеры. Я же буду показывать примеры на нашей области применения – на акциях.
Итак, вот пример объекта:
Stock = {
name = 'SBER',
code = 'TQBR',
price = 255,
lots = 12
}
Это приведен пример объекта только со свойствами, без методов. Все свойства равны пустым значениям. Теперь ими можно оперировать и переприсваивать значения. Например, так:
Stock.name = 'ROSN'
Stock.price = 290
И так далее.
Это пример объекта только со свойствами, без методов. Давайте добавим какой-нибудь метод в данный объект. Например, это будет метод, который возвращает шаг цены по инструменту.
function Stock:giveStepPrice()
local info_po_bum = getSecurityInfo(self.code,self.name);
result = 0;
if (info_po_bum) then
result = info_po_bum["min_price_step"];
end
return result;
end
Обратите внимание, что запись «self» говорит, что обращение идет к текущему объекту, то есть к Stock и в вычислениях использует свойства этого объекта.
Теперь, если написать так:
aaa = Stock:giveStepPrice();
То, в переменной ааа будет находиться шаг цены по данному инструменту.
Таких методов в объекте может быть много.
Итак, надеюсь, что разобрались с этим.
В классических Си-подобных языках программирования при оперировании с ООП есть понятие класс – это своего рода шаблон для создания объектов. При описании класса указывают какие свойства и методы будут в объектах, которые будут создаваться на основе этого класса.
Например, в нашем случае могло бы быть. Класс акция, в котором указано, что у акции есть код, код класса, количество лотов, которыми мы будем работать, цена по которой мы будем работать и пр. Также класс может содержать методы определения текущей рыночной цены, определения шага цены и пр. И на основе этого класса могут создаваться конкретные объекты. Например, объект акций Сбера. В этом объекте уже будет прописано название – SBER, код класса – TQBR и т.д.
В Си-подобных языках программирования создание новых объектов на базе класса прописывается примерно так:
Stock_SBER = new Stock();
Где – Stock – класс, на основе которого создается объект Stock_SBER.
Так вот…. В LUA нет классов!
И автор данного языка программирования в качестве альтернативы предлагает создавать базовый объект, который будет являться шаблоном для создания других объектов. И, вот этот базовый объект как бы и будет классом.
Давайте напишем базовый объект Stock и на его базе создадим парочку других объектов-акций.
Вот так создаем базовый объект:
Stock = {
name = '',
code = 'TQBR',
price = 0,
lots = 0
}
function Stock:giveStepPrice()
local info_po_bum = getSecurityInfo(self.code,self.name);
result = 0;
if (info_po_bum) then
result = info_po_bum["min_price_step"];
end
return result;
end
На его базе создаются новые объекты так:
Stock_SBER = {}
setmetatable (Stock_SBER, {__index = Stock});
Stock_SBER.name = "SBER"
Stock_SBER.price = 255
Stock_SBER.lots = 12
Stock_ROSN = {}
setmetatable (Stock_ROSN, {__index = Stock});
Stock_ROSN.name = "ROSN"
Stock_ROSN.price = 444
Stock_ROSN.lots = 5
То есть, сначала объект инициализируется как таблица с помощью фигурных скобок, а потом с помощью такой комбинации он создается на основе базового объекта:
setmetatable (Stock_SBER, {__index = Stock});
Надеюсь, что Вам тут всё понятно, потому что мне самому многое в деталях не ясно.
Если после создания так двух объектов мы запустим такой код:
message("Stock_SBER.name = "..Stock_SBER.name);
message("Stock_SBER.code = "..Stock_SBER.code);
message("Stock_SBER.price = "..Stock_SBER.price);
message("Stock_SBER.lots = "..Stock_SBER.lots);
message("Stock_SBER.lots:giveStepPrice() = "..Stock_SBER:giveStepPrice())
message("===================================");
message("Stock_ROSN.name = "..Stock_ROSN.name);
message("Stock_ROSN.code = "..Stock_ROSN.code);
message("Stock_ROSN.price = "..Stock_ROSN.price);
message("Stock_ROSN.lots = "..Stock_ROSN.lots);
message("Stock_ROSN.lots:giveStepPrice() = "..Stock_ROSN:giveStepPrice())
То, в таблице сообщений получим следующее:
Обратите внимание, что мы при создании объектов не меняли свойство code. Но, оно вывелось у обоих объектов как TQBR. Это значение было перенесено из базового объекта (класса).
Так же обратите внимание, что метод отработал и для каждой бумаги определил шаг цены.
В общем-то, на этом можно было бы закончить. Единственное, я хотел бы поделиться одной ситуацией, с которой сам столкнулся. Мне нужно было в свойство объекта с именем days_week добавить таблицу (массив). В нем указывалось в какой день недели идут торги по этой бумаге, а в какой не идут.
Дело в том, что если просто прописать базовый объект так:
days_week_baza = {}
Stock = {
name = '',
code = 'TQBR',
price = 0,
days_week = days_week_baza,
lots = 0
}
И потом на его основе создавать объекты, то будет проблема, связанная с тем, что у всех объектов будет не свой массив значений days_week, а ссылка на один и тот же массив.
Что бы избежать такой ситуации необходимо на базе таблицы days_week_baza создавать объект для каждой акции. То есть синтаксис должен быть такой при создании нового объекта акции:
week_days_sber = {}
setmetatable (week_days_sber, {__index = days_week_baza });
Stock_SBER = {}
setmetatable (Stock_SBER, {__index = Stock});
Stock_SBER. days_week = week_days_sber
То есть, сначала создается объект для свойства дней недели, потом создается объект акций. И потом прописывается, что в свойстве конкретной акции как день недели должен быть ранее созданный объект таблицы дней недели.
Надеюсь, что я вас не запутал.
🧐 Посмотреть код данного выпуска
В этой статье я показал некоторые основные моменты работы с ООП. Безусловно, ООП является достаточно сложной системой программирования. И на основе ООП строится множество различных механизмов, или паттернов проектирования. Так, в 1994 году группой авторов, которых в среде программистов называют «бандой четырех» была написана книга «Design Patterns». В этой книге авторы описали множество схем построения различных систем. И, во многом уровень программиста зависит от того насколько он посвящен в эти паттерны и умеет их применять на практике, используя тот язык программирования, на котором он специализируется.
На этом у меня все.
Всем удачи – всем пока!
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇
📃 Краткое содержание данного канала.
➖➖➖➖➖➖➖➖➖➖➖➖➖
Landingcentr.ru - разработка сайтов для малого и среднего бизнеса.
⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆⬆