Добавлен , опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
Lua
Тип:
Наработка
Версия Warcraft:
1.31+
Представляю Вам свою реализацию классов для lua. Классы создаются статически. На данный момент позволяет использовать области видимости static, public и override (private существует отдельно от наработки). Реализовано наследование. Основной задачей было организовать однородную структуру кода вне зависимости от выполняемой задачи и совместимость с EmmyLua (VsCode Lua от sumneko). Буду рад объективной критике. Исправлены ошибки и все объединено в одну область do-end.
API
((
ClassAPI.new(name, parents)
Создание нового класса. Для созданного класса доступны для редактирования
только поля public, static и override. Для скрытия полей public и override рекомендуется
возвращать из области do-end поле static полученного класса.
name : string - имя нового класса.
parents : vararg - список родителей класса в порядке приоритетности.
return table
ClassAPI.allocate(class)
Создание инстанса класса.
class : table - класс созданный с помощью функции ClassAPI.new.
return table
ClassAPI.isClass(var)
Проверяет является ли переменная классом.
var : any
return boolean
ClassAPI.isInstance(var)
Проверяет является ли переменная инстансом любого класса.
var : any
return boolean
ClassAPI.getClass(instance)
Возвращает класс инстанса.
instance : table - инстанс класса созданный с помощью ClassAPI.allocate.
return table
ClassAPI.isChild(class1, class2)
Проверяет является ли класс наследником.
class1 : table - класс созданный с помощью функции ClassAPI.new.
class2 : table - класс созданный с помощью функции ClassAPI.new.
return boolean
ClassAPI.getPublic(static)
Позволяет получить поле public того же класса. Необходимо для реализации виртуальных функций.
static : table - поле класса "static"
return table - поле класс "public"
ClassAPI.getOverride(static)
Позволяет получить поле override того же класса. Необходимо для реализации статических
виртуальных функций.
static : table - поле класса "static"
return table - поле класс "override"
ClassAPI.type = ClassDeclare.type
))
Пример класса с использованием наработки:
Action
--=========
-- Include
--=========

local lib_modname = Lib.current().modname

local Class = Lib.current().depencies.Class -- Равноценно local Class = ClassAPI

---@type LoggerClass
local Logger = require(lib_modname..'.Logger')
local Log = Logger.getDefault()
---@type UtilsFunctions
local Functions = require(lib_modname..'.Functions')
local checkType = Functions.checkType

--=======
-- Class
--=======

local Action = Class.new('Action')
---@class Action
local public = Action.public
---@class ActionClass
local static = Action.static
---@type ActionClass
local override = Action.override
local private = {}

--========
-- Static
--========

---@alias Callback fun(vararg:any[]):any

---@param callback Callback
---@param owner any
---@param child_instance Action | nil
---@return Action
function override.new(callback, owner, child_instance)
    checkType(callback, 'function', 'callback')
    if child_instance then
        checkType(child_instance, 'Action', 'child_instance')
    end

    local instance = child_instance or Class.allocate(Action)
    private.newData(instance, callback, owner)

    return instance
end

--========
-- Public
--========

function public:run(...)
    if private.debug then
        local success, result = pcall(private.data[self].callback, ...)
        if success then
            return result
        else
            Log:err(result)
        end
    else
        return private.data[self].callback(...)
    end
end

---@return any
function public:getOwner()
    return private.data[self].owner
end

--=========
-- Private
--=========

private.data = setmetatable({}, {__mode = 'k'})

private.debug = true

---@param self Action
---@param callback Callback
---@param owner any
function private.newData(self, callback, owner)
    local priv = {
        callback = callback,
        owner = owner
    }
    private.data[self] = priv
end

return static
Функция checkType
---@param var any
---@param need_type any
---@param var_name string
---@param level number | nil
function UtilsFunctions.checkType(var, need_type, var_name, level)
    if not debug then
        return
    end

    local real_type = type(var)
    if real_type == 'userdata' then
        local wc3_type_string = tostring(var)
        local pos = wc3_type_string:find(':')
        local wc3_type = wc3_type_string:sub(1, pos - 1)
        if wc3_type ~= need_type then
            Log:err('variable \''..(var_name or '')..'\'('..wc3_type..') is not of type '..tostring(need_type), level or 3)
        end
        return
    end

    if not ClassAPI.classType(var, need_type) then
        Log:err('variable \''..(var_name or '')..'\' is not of type '..tostring(need_type), level or 3)
    end
end
Использование:
local action = Action.new(function(a, b) return a/b end)
action:run(1, 0)

--[[ Будет выведена ошибка деление на нуль с указание номера строки "local action = Action.new(function(a, b) return a/b end)" ]]
Класс Action позволяет безопасно запускать функции при private.debug = true. Использую его для действий триггеров, таймеров и т.д, что позволяет оперативно найти ошибку в коде.
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
38
Опередил)
На самом деле, стоит адекватно уделить время этой теме и написать серьезные обучающие статьи на этот счёт.
13
ScorpioT1000, да, было бы неплохо всю инфу по lua разжевать и залить в одно место. А я только пару дней назад узнал, что у функции error есть второй параметр, который крайне необходим в реалиях wc3
28
Стоит убрать старые статьи, либо чутка обновить их, то же введение в JASS.
33
А можно немножечко для тех кто в танке и не понимает зачем это вообще нужно:
  1. Что это даст?
  2. Тем кто не понимает, нужно ли это изучать?
  3. Что те кто не понимают этого, что они теряют?
38
Bergi_Bear, в процедурном программировании даже при максимально красивом коде приходит момент, когда начинается кошмар и путаница

Хотя_можно_писать_много_префиксов_func()
13
ScorpioT1000, в луа это можно решить либами на основе таблиц. Тут больше в мировоззрении дело и в поставленной задаче. Где-то удобнее ООП, где-то функциональное...
31
Что это даст?
В вашем коде будет ООП ради ООП
Тем кто не понимает, нужно ли это изучать?
В таких наработках нужно смотреть на примеры - если они сферические в вакууме, то скорей всего ООП не решает задачи, а создаёт проблемы.
в процедурном программировании даже при максимально красивом коде приходит момент, когда начинается кошмар и путаница
ООП не серебрянная пуля и не лечит кошмар и путаницу.
Тут больше в мировоззрении дело и в поставленной задаче.
Я так понимаю, задача была реализовать ООП в луа?
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.