Menu
Coddy logo textTech

Duck Typing

Parte da seção Programação Orientada a Objetos do Journey de Lua da Coddy. Lição 39 de 70.

Lua não se importa com a classe de um objeto. Ela só se importa com o que o objeto pode fazer. Esse conceito é chamado de tipagem pato: "Se ele anda como um pato e grasna como um pato, é um pato." Em termos de programação, se um objeto tem o método que você está chamando, ele funciona.

Isso significa que classes completamente não relacionadas podem ser usadas juntas, desde que compartilhem o mesmo nome de método:

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

Essas classes não têm uma relação de herança: são completamente independentes. Ainda assim, podemos tratá-las de forma idêntica:

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

for _, shape in ipairs(shapes) do
    shape:draw()
end
-- Saída:
-- Desenhando um círculo
-- Desenhando um quadrado
-- Desenhando um círculo

O loop não verifica qual é o tipo de cada objeto. Ele simplesmente chama :draw() e confia que o método existe. Essa flexibilidade é poderosa. Você pode adicionar novos tipos de formas sem modificar o código do loop. Desde que a nova classe implemente :draw(), tudo funciona.

challenge icon

Desafio

Fácil

Vamos demonstrar o poder da tipagem pato construindo um sistema de notificações com classes completamente independentes que podem ser todas processadas da mesma maneira!

Você criará três classes de notificação independentes, nenhuma delas herdando da outra, mas todas implementando um método :send(). Isso significa que você pode percorrer uma coleção mista e chamar :send() em cada elemento sem se preocupar com seu tipo real.

Você organizará seu código em quatro arquivos:

  • Email.lua: Uma classe com um construtor :new(recipient) que armazena para quem o e-mail será enviado. Seu método :send() deve imprimir Emailing {recipient}.
  • SMS.lua: Uma classe completamente separada com um construtor :new(phoneNumber). Seu método :send() deve imprimir Texting {phoneNumber}.
  • PushNotification.lua: Outra classe independente com um construtor :new(deviceId). Seu método :send() deve imprimir Pushing to {deviceId}.
  • main.lua: Junte tudo! Leia três entradas, crie uma instância de cada tipo de notificação, coloque todas em uma única tabela e, em seguida, percorra a tabela chamando :send() em cada uma.

Você receberá três entradas:

  1. Um destinatário de e-mail (por exemplo, alice@example.com)
  2. Um número de telefone (por exemplo, 555-1234)
  3. Um ID de dispositivo (por exemplo, device_99)

Em seu arquivo principal, crie os três objetos de notificação, armazene-os em uma tabela e percorra a tabela chamando :send() em cada um. A ordem deve ser: primeiro Email, depois SMS e, por fim, PushNotification.

Por exemplo, se as entradas forem bob@mail.com, 555-9876 e phone_42, a saída deverá ser:

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

Observe como seu loop não precisa verificar qual é o tipo de cada objeto. Ele simplesmente confia que todo objeto da coleção possui um método :send(). Isso é a tipagem pato em ação! Se ele pode executar :send(), é uma notificação.

Experimente você mesmo

-- main.lua
-- Reúna todos os tipos de notificação e demonstre duck typing

-- Importe as classes de notificação
local Email = require('Email')
local SMS = require('SMS')
local PushNotification = require('PushNotification')

-- Leia as entradas
local recipient = io.read()
local phoneNumber = io.read()
local deviceId = io.read()

-- TODO: Crie uma instância de cada tipo de notificação

-- TODO: Coloque todas as notificações em uma única tabela (Email primeiro, depois SMS, depois PushNotification)

-- TODO: Percorra a tabela e chame :send() em cada notificação
-- Isso demonstra duck typing - não verificamos o tipo, apenas chamamos :send()
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Lua online