Sprawdzanie równości
Część sekcji Programowanie obiektowe ścieżki Lua w Coddy. Lekcja 17 z 70.
Wiesz już, jak __tostring określa sposób wyświetlania obiektu. Inną przydatną metametodą jest __eq, która definiuje, kiedy dwa obiekty należy uznać za równe przy użyciu operatora ==.
Domyślnie porównanie dwóch tabel za pomocą == sprawdza, czy są dokładnie tą samą tabelą w pamięci. Dwa oddzielne obiekty z identycznymi danymi zwrócą false:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Wynik: false (różne tabele)Za pomocą __eq możesz zdefiniować własną logikę równości. W klasie dodajesz ją tak samo jak __tostring — jako funkcję w tabeli klasy. Aby porównywanie równości działało, oba obiekty muszą mieć tę samą metatabelę:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endTeraz dwa obiekty User są uznawane za równe, jeśli mają ten sam identyfikator, niezależnie od pozostałych pól:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Wynik: true (ten sam ID)
print(u1 == u3) -- Wynik: false (różne IDs)Ten wzorzec jest przydatny, gdy obiekty reprezentują rzeczywiste byty o unikalnych identyfikatorach: przy porównywaniu rekordów w bazie danych, obiektów w grach lub dowolnych obiektów, w przypadku których tożsamość ma większe znaczenie niż lokalizacja w pamięci.
Wyzwanie
ŁatwyZbudujmy klasę Product, która potrafi określić, czy dwa produkty są tym samym artykułem, nawet jeśli są przechowywane w zupełnie różnych tabelach! W systemach sprzedaży detalicznej produkty często mają unikalne kody SKU (Stock Keeping Units), a dwa produkty należy uznać za równe, jeśli mają takie samo SKU, niezależnie od innych szczegółów, takich jak zmiany ceny.
Podzielisz swój kod na dwa pliki:
Product.lua: Zdefiniuj klasęProductprzy użyciu standardowego wzorca prototypu. Każdy produkt powinien przechowywaćsku(unikalny identyfikator) iname. Zaimplementuj metametodę__eq, aby dwa produkty były uznawane za równe, gdy mają takie samo SKU: nazwa nie ma znaczenia przy porównywaniu.main.lua: Załaduj moduł Product i utwórz kilka instancji produktów. Porównaj je za pomocą operatora==, aby zobaczyć działanie własnej logiki porównywania równości.
Twoja klasa Product powinna zawierać:
- Konstruktor
:new(sku, name) - Metodę
:getInfo(), która zwraca ciąg znaków w formacie:[sku]: [name] - Metametodę
__eq, która porównuje produkty według ich SKU
Otrzymasz sześć danych wejściowych:
- SKU pierwszego produktu
- Nazwę pierwszego produktu
- SKU drugiego produktu
- Nazwę drugiego produktu
- SKU trzeciego produktu
- Nazwę trzeciego produktu
W głównym pliku utwórz trzy produkty przy użyciu podanych danych wejściowych, a następnie wypisz:
- Informacje o każdym produkcie (trzy wiersze)
- Wynik porównania produktu 1 z produktem 2
- Wynik porównania produktu 1 z produktem 3
Na przykład, jeśli danymi wejściowymi są ABC123, Wireless Mouse, ABC123, Mouse (Updated), XYZ789 i Keyboard, wynikiem powinno być:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
falseZwróć uwagę, że pierwsze dwa produkty są równe (mają takie samo SKU), mimo że ich nazwy się różnią. Właśnie w ten sposób rzeczywiste systemy magazynowe śledzą produkty, gdy zmieniają się ich nazwy i są aktualizowane!
Spróbuj swoich sił
-- Załaduj moduł Product
local Product = require('Product')
-- Odczytaj dane wejściowe
local sku1 = io.read()
local name1 = io.read()
local sku2 = io.read()
local name2 = io.read()
local sku3 = io.read()
local name3 = io.read()
-- TODO: Utwórz trzy instancje Product, używając danych wejściowych
-- TODO: Wypisz informacje o każdym produkcie (trzy wiersze)
-- TODO: Wypisz wynik porównania produktu 1 z produktem 2
-- TODO: Wypisz wynik porównania produktu 1 z produktem 3
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Koncepcja „self”
Tabele z funkcjamiJawne „self”Składnia z dwukropkiemKropka czy dwukropekPodsumowanie — poruszający się punkt4Projekt: Bank cyfrowy
Konfiguracja projektuMetoda wpłaty7Polimorfizm i nadpisywanie
Nadpisywanie metodWywoływanie metod klasy nadrzędnejTypowanie kaczeWspólny interfejsSprawdzanie typuPodsumowanie — role pracowników10Projekt: Menedżer kształtów
Konfiguracja projektuKlasa prostokątaKlasa kołaMetoda obwoduKolekcja kształtówPole całkowiteFiltrowanie kształtów2Wzorzec prototypu klasy
Koncepcja prototypuŁączenie za pomocą __indexKonstruktor :new()Inicjalizacja atrybutówNiezależne instancjePodsumowanie – fabryka samochodów5Przeciążanie operatorów w OOP
Dodawanie obiektówOdejmowanie obiektówŁączenie obiektówPorównywanie obiektów (<, >)Powtórka — działania na portfelu8Hermetyzacja
Konwencje nazewnictwaDomknięcia dla prywatnościDostęp za pomocą domknięćTabele tylko do odczytuLogika walidacjiPodsumowanie — bezpieczny sejf11Wzorce projektowe (podstawy)
Funkcje fabrykująceTabela SingletonWzorzec iteratoraObserwator (nasłuchujący)Powtórka — fabryka loggera3Stan i zachowanie obiektu
Zmienne instancjiMetody dostępoweMetody ustawiająceWłaściwości obliczaneFormatowanie ciągów znakówSprawdzanie równościPodsumowanie – ocena ucznia6Podstawy dziedziczenia
Konfiguracja dziedziczeniaDziedziczenie metodRozszerzanie konstruktoraDodawanie metod potomnychWspólne i unikalne elementyPowtórka — hierarchia kształtówPoćwicz samodzielnie: Kompilator Lua online