Menu
Coddy logo textTech

Duck Typing

Teil des Abschnitts Objektorientierte Programmierung der Lua-Journey von Coddy. Lektion 39 von 70.

Lua ist die Klasse eines Objekts egal. Es zählt nur, was das Objekt tun kann. Dieses Konzept wird Duck-Typing genannt: „Wenn es wie eine Ente läuft und wie eine Ente quakt, ist es eine Ente.“ In der Programmierung bedeutet das: Wenn ein Objekt über die Methode verfügt, die du aufrufst, funktioniert es.

Das bedeutet, dass völlig unabhängige Klassen zusammen verwendet werden können, solange sie denselben Methodennamen haben:

local Circle = {}
Circle.__index = Circle
function Circle:new() 
    local obj = {}
    setmetatable(obj, Circle)
    return obj
end
function Circle:draw()
    print("Drawing a circle")
end

local Square = {}
Square.__index = Square
function Square:new()
    local obj = {}
    setmetatable(obj, Square)
    return obj
end
function Square:draw()
    print("Drawing a square")
end

Diese Klassen haben keine Vererbungsbeziehung: Sie sind vollständig unabhängig. Dennoch können wir sie identisch behandeln:

local shapes = {Circle:new(), Square:new(), Circle:new()}

for _, shape in ipairs(shapes) do
    shape:draw()
end
-- Ausgabe:
-- Zeichne einen Kreis
-- Zeichne ein Quadrat
-- Zeichne einen Kreis

Die Schleife prüft nicht, welchen Typ jedes Objekt hat. Sie ruft einfach :draw() auf und vertraut darauf, dass die Methode existiert. Diese Flexibilität ist äußerst leistungsfähig. Du kannst neue Formtypen hinzufügen, ohne den Code der Schleife überhaupt zu ändern. Solange die neue Klasse :draw() implementiert, funktioniert sie einfach.

challenge icon

Aufgabe

Einfach

Demonstrieren wir die Leistungsfähigkeit von Duck-Typing, indem wir ein Benachrichtigungssystem mit völlig unabhängigen Klassen erstellen, die alle auf dieselbe Weise verarbeitet werden können!

Du erstellst drei unabhängige Benachrichtigungsklassen, von denen keine von einer anderen erbt, die aber alle eine :send()-Methode implementieren. Das bedeutet, dass du eine gemischte Sammlung durchlaufen und für jedes Element :send() aufrufen kannst, ohne dich um seinen tatsächlichen Typ kümmern zu müssen.

Du organisierst deinen Code auf vier Dateien verteilt:

  • Email.lua: Eine Klasse mit einem :new(recipient)-Konstruktor, der speichert, an wen die E-Mail gesendet wird. Ihre :send()-Methode soll Emailing {recipient} ausgeben.
  • SMS.lua: Eine vollständig separate Klasse mit einem :new(phoneNumber)-Konstruktor. Ihre :send()-Methode soll Texting {phoneNumber} ausgeben.
  • PushNotification.lua: Eine weitere unabhängige Klasse mit einem :new(deviceId)-Konstruktor. Ihre :send()-Methode soll Pushing to {deviceId} ausgeben.
  • main.lua: Führe alles zusammen! Lies drei Eingaben ein, erstelle eine Instanz jedes Benachrichtigungstyps, füge sie alle in eine einzige Tabelle ein, durchlaufe sie anschließend und rufe für jedes Element :send() auf.

Du erhältst drei Eingaben:

  1. Einen E-Mail-Empfänger (z. B. alice@example.com)
  2. Eine Telefonnummer (z. B. 555-1234)
  3. Eine Geräte-ID (z. B. device_99)

Erstelle in deiner Hauptdatei alle drei Benachrichtigungsobjekte, speichere sie in einer Tabelle und durchlaufe die Tabelle, wobei du für jedes Element :send() aufrufst. Die Reihenfolge sollte sein: zuerst Email, dann SMS und anschließend PushNotification.

Wenn die Eingaben beispielsweise bob@mail.com, 555-9876 und phone_42 lauten, sollte die Ausgabe wie folgt aussehen:

Emailing bob@mail.com
Texting 555-9876
Pushing to phone_42

Beachte, dass deine Schleife nicht überprüfen muss, welchen Typ jedes Objekt hat. Sie vertraut einfach darauf, dass jedes Objekt in der Sammlung über eine :send()-Methode verfügt. Genau das ist Duck-Typing in Aktion! Wenn es :send() kann, ist es eine Benachrichtigung.

Probier es selbst

-- main.lua
-- Alle Benachrichtigungstypen zusammenbringen und Duck Typing demonstrieren

-- Die Benachrichtigungsklassen importieren
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')

-- Eingaben lesen
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()

-- TODO: Erstelle eine Instanz von jedem Benachrichtigungstyp

-- TODO: Lege alle Benachrichtigungen in eine einzige Tabelle (Email zuerst, dann SMS, dann PushNotification)

-- TODO: Durchlaufe die Tabelle und rufe :send() für jede Benachrichtigung auf
-- Dies demonstriert Duck Typing – wir prüfen den Typ nicht, wir rufen einfach :send() auf
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Lua-Compiler