Wzorce modułów i dobre praktyki
Proszę używać wzorca local M = {} i przejrzyście udostępniać publiczne API.
Wzorce modułów i dobre praktyki to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.
Wzorzec M = {}
Uniwersalny wzorzec modułu Lua: zadeklaruj lokalną tabelę, wypełnij ją i zwróć. Wszystkie publiczne symbole umieść w M, a wszystkie prywatne funkcje pomocnicze pozostaw jako zwykłe zmienne lokalne. Jest to rozwiązanie przejrzyste, minimalistyczne i działające wszędzie.
-- The canonical module pattern
local M = {}
-- Private helper (not exported)
local function validate(x)
return type(x) == "number" and x >= 0
end
-- Public API
function M.sqrt(x)
assert(validate(x), "expected non-negative number")
return math.sqrt(x)
end
M.PI = math.pi
return MModuł odwołujący się do samego siebie
Wewnątrz modułu funkcje mogą wywoływać inne funkcje modułu albo za pomocą nazwy (M.foo()), albo jako zmienne lokalne. Używanie zmiennych lokalnych jest nieco szybsze, natomiast użycie M.foo() pozwala użytkownikom zastąpić M.foo, dzięki czemu wewnętrzne wywołanie użyje zastąpionej wersji (monkey patching).
local M = {}
-- Option A: use M.foo inside (allows override)
function M.double(n) return M.multiply(n, 2) end
function M.multiply(a, b) return a * b end
-- Option B: use local function (faster, no override)
local function mul(a, b) return a * b end
function M.triple(n) return mul(n, 3) end
return MWzorzec Singleton
Moduł może działać jako singleton: mieć zmienny stan wewnętrzny współdzielony przez wszystkich wywołujących. Ponieważ require zapisuje moduł w pamięci podręcznej, wszystkie wywołania require("mod") otrzymują ten sam obiekt z tym samym stanem.
-- config.lua (singleton)
local M = {}
local _config = {env="dev", logLevel="info"}
function M.set(key, val)
_config[key] = val
end
function M.get(key)
return _config[key]
end
function M.load(t)
for k,v in pairs(t) do _config[k]=v end
end
return M
-- All callers share the same config:Moduł jako przestrzeń nazw
Używaj modułu wyłącznie jako przestrzeni nazw, aby uniknąć zaśmiecania tabeli globalnej. Grupuj powiązane stałe i narzędzia pod jedną nazwą, podobnie jak pakiet w innych językach.
-- constants.lua
local M = {
HTTP = {
OK=200, CREATED=201, NO_CONTENT=204,
BAD_REQUEST=400, UNAUTHORIZED=401,
NOT_FOUND=404, SERVER_ERROR=500,
},
COLORS = {RED="#FF0000", GREEN="#00FF00", BLUE="#0000FF"},
MAX_RETRIES = 3,
TIMEOUT_SEC = 30,
}
return M
-- local C = require("constants")
-- if status == C.HTTP.NOT_FOUND then ...Moduł fabrykujący
Jest to moduł, który eksportuje funkcję fabrykującą zamiast zwykłej tabeli. Fabryka tworzy i zwraca nowe instancje z własnym prywatnym stanem. Jest to wzorzec klasy zastosowany na poziomie modułu.
-- logger.lua
local M = {}
function M.new(name, level)
level = level or "info"
local levels = {debug=1,info=2,warn=3,error=4}
local self = {}
function self.log(msgLevel, msg)
if levels[msgLevel] >= levels[level] then
print(string.format("[%s][%s] %s", name, msgLevel:upper(), msg))
end
end
function self.info(msg) self.log("info", msg) end
function self.warn(msg) self.log("warn", msg) end
function self.error(msg) self.log("error", msg) end
return self
end
return MFunkcja inicjalizująca modułu
Niektóre moduły wymagają konfiguracji przed użyciem. Udostępnij funkcję M.init(config), która zapisze konfigurację w prywatnym stanie modułu. Umożliwia to wstrzykiwanie zależności i ułatwia testowanie.
-- db.lua
local M = {}
local pool = nil
function M.init(config)
pool = {
host = config.host or "localhost",
port = config.port or 5432,
connections = {},
}
print("DB initialized:", pool.host, pool.port)
end
function M.query(sql)
assert(pool, "call db.init() first")
-- ... execute query
return {}
end
return MNiemutowalny moduł
Zapobiegaj przypadkowym modyfikacjom API modułu przez użytkowników, używając __newindex do blokowania wszystkich zapisów. Jest to szczególnie przydatne w modułach bibliotek, w których przypadkowy monkey patching mógłby spowodować nieprawidłowe działanie.
local function freeze(t)
return setmetatable({}, {
__index = t,
__newindex = function(_, k, _)
error("module is read-only, cannot set: " .. tostring(k), 2)
end
})
end
local M = {}
function M.add(a, b) return a + b end
function M.sub(a, b) return a - b end
return freeze(M)Dokumentowanie za pomocą LDoc
Popularną konwencją dokumentowania modułów Lua są komentarze w stylu LDoc z prefiksem ---. Choć język ich nie wymusza, komentarze te umożliwiają narzędziom do generowania dokumentacji automatyczne tworzenie dokumentacji API.
--- A utility module for string operations.
-- @module stringutils
local M = {}
--- Trim leading and trailing whitespace.
-- @param s string The input string.
-- @return string The trimmed string.
function M.trim(s)
return s:match("^%s*(.-)%s*$")
end
--- Count occurrences of a substring.
-- @param str string The string to search.
-- @param sub string The substring to count.
-- @return number Count of occurrences.
function M.count(str, sub)
local _, n = str:gsub(sub, "")
return n
end
return MTestowanie modułów
Testuj moduł, wymagając go i sprawdzając działanie każdej funkcji. Użyj prostego narzędzia do uruchamiania testów albo busted (frameworka testowego dla Lua). Przechowuj testy w osobnym pliku odwzorowującym ścieżkę modułu.
-- test/test_stringutils.lua
local su = require("stringutils")
local function test(name, fn)
local ok, err = pcall(fn)
if ok then print("[PASS] " .. name)
else print("[FAIL] " .. name .. ": " .. err)
end
end
test("trim removes spaces", function()
assert(su.trim(" hello ") == "hello")
end)
test("trim empty string", function()
assert(su.trim("") == "")
end)
test("count occurrences", function()
assert(su.count("banana", "a") == 3)
end)Komponowanie modułów
Złożone systemy tworzy się z wielu modułów. Główny punkt wejścia wymaga podmodułów i łączy je ze sobą. Taki podział odpowiedzialności pozwala zachować koncentrację każdego modułu na określonym zadaniu i niezależnie go testować.
-- app.lua (main entry point)
local config = require("config")
local db = require("db")
local server = require("server")
-- Configure from environment
config.load({
dbHost = os.getenv("DB_HOST") or "localhost",
port = tonumber(os.getenv("PORT")) or 8080,
})
-- Wire modules together
db.init({host=config.get("dbHost"), port=5432})
server.init({port=config.get("port"), db=db})
server.start()Szybkie sprawdzenie
Jaki jest główny cel wzorca modułu local M = {} ... return M?
Podsumowanie: dobre praktyki dotyczące modułów
Podsumowanie:
- Zawsze stosuj
local M = {} ... return M - Prywatne = zmienne lokalne na poziomie pliku; publiczne = pola M
- Singleton: require zapisuje instancję modułu w pamięci podręcznej
- Używaj funkcji fabrykujących dla stanu niezależnego dla każdej instancji
- Zamrażaj moduły za pomocą __newindex, aby zapobiegać modyfikacjom
- Testy umieszczaj w osobnych plikach; dokumentuj za pomocą komentarzy ---
Często zadawane pytania
Czy lekcja „Wzorce modułów i dobre praktyki” jest bezpłatna?
Tak — pełny tekst „Wzorce modułów i dobre praktyki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wzorce modułów i dobre praktyki”?
Proszę używać wzorca local M = {} i przejrzyście udostępniać publiczne API. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Lua Academy?
Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Wzorce modułów i dobre praktyki”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?
Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Funkcja require
- Tworzenie pliku modułu
- package.path i package.cpath
- Wzorce modułów i dobre praktyki