SwiftHTML & CSSSolidityDesenvolvimento de JogosSolana/Rust
26.11.2024

Aula 146: Técnicas Avançadas de Ocultação de Tipo

A ocultação de tipo é um conceito poderoso em Swift que permite trabalhar com tipos heterogêneos de maneira segura em termos de tipo. Esta aula o guiará por técnicas avançadas de ocultação de tipo, mostrando como você pode criar componentes flexíveis e reutilizáveis.

Entendendo a Ocultação de Tipo

A ocultação de tipo é uma forma de esconder o tipo específico de valores atrás de uma interface comum, o que pode ser particularmente útil ao trabalhar com tipos genéricos e protocolos. Em Swift, protocolos com tipos associados podem ser desafiadores devido à sua incapacidade de serem usados diretamente em coleções ou em outros contextos que exigem um tipo concreto. A ocultação de tipo nos ajuda a superar essas limitações.

Criando uma Ferramenta de Ocultação de Tipo

Vamos criar uma ferramenta simples de ocultação de tipo para um protocolo que possui um tipo associado. Considere um protocolo Desenhavel que representa objetos que podem ser desenhados.

protocol Desenhavel {
    associatedtype Saída
    func desenhar() -> Saída
}

Agora, vamos criar um wrapper de ocultação de tipo chamado QualquerDesenhavel. Este wrapper encapsulará qualquer tipo que conforma ao Desenhavel.

struct QualquerDesenhavel<Saída>: Desenhavel {
    private let _desenhar: () -> Saída

    init<T: Desenhavel>(_ desenhavel: T) where T.Saída == Saída {
        _desenhar = desenhavel.desenhar
    }

    func desenhar() -> Saída {
        return _desenhar()
    }
}

Explicação

Na struct QualquerDesenhavel:

  • Definimos uma closure privada _desenhar para armazenar o comportamento do método desenhar.
  • O inicializador recebe qualquer tipo que conforma a Desenhavel e extrai seu método desenhar.
  • O método desenhar() de QualquerDesenhavel simplesmente chama a closure armazenada.

Exemplo de Uso

Vamos ver como essa ocultação de tipo funciona na prática. Primeiro, criaremos alguns tipos que conformam ao Desenhavel.

struct Circulo: Desenhavel {
    var raio: Double

    func desenhar() -> String {
        return "Desenhando um círculo com raio \(raio)"
    }
}

struct Quadrado: Desenhavel {
    var comprimentoLado: Double

    func desenhar() -> String {
        return "Desenhando um quadrado com comprimento do lado \(comprimentoLado)"
    }
}

Agora, podemos criar instâncias de Circulo e Quadrado, envolvê-las em QualquerDesenhavel e armazená-las em uma coleção.

let formas: [QualquerDesenhavel<String>] = [
    QualquerDesenhavel(Circulo(raio: 5)),
    QualquerDesenhavel(Quadrado(comprimentoLado: 10))
]

for forma in formas {
    print(forma.desenhar())
}

Saída

Desenhando um círculo com raio 5.0
Desenhando um quadrado com comprimento do lado 10.0

Benefícios da Ocultação de Tipo

  1. Flexibilidade: A ocultação de tipo permite que você trabalhe com vários tipos de maneira uniforme, tornando seu código mais flexível.
  2. Abstração: Você pode definir interfaces sem se preocupar com as implementações subjacentes.
  3. Separação de Preocupações: A ocultação de tipo ajuda a manter seu código modular, separando a interface da implementação.

Ocultação de Tipo Avançada: Lidando com Múltiplos Tipos Associados

Em casos onde um protocolo possui múltiplos tipos associados, o processo permanece conceitualmente similar, mas adiciona complexidade. Você pode usar agrupamento por tupla para múltiplos tipos associados:

protocol MultiDesenhavel {
    associatedtype A
    associatedtype B
    func desenhar() -> (A, B)
}

struct QualquerMultiDesenhavel<A, B>: MultiDesenhavel {
    private let _desenhar: () -> (A, B)

    init<T: MultiDesenhavel>(_ desenhavel: T) where T.A == A, T.B == B {
        _desenhar = desenhavel.desenhar
    }

    func desenhar() -> (A, B) {
        return _desenhar()
    }
}

Exemplo de Uso

Implemente um tipo que conforma a MultiDesenhavel:

struct Retangulo: MultiDesenhavel {
    var largura: Double
    var altura: Double

    func desenhar() -> (String, String) {
        return ("Desenhando retângulo com largura \(largura)", "e altura \(altura)")
    }
}

let formas2: [QualquerMultiDesenhavel<String, String>] = [
    QualquerMultiDesenhavel(Retangulo(largura: 4, altura: 2))
]

for forma in formas2 {
    let (desc1, desc2) = forma.desenhar()
    print(desc1)
    print(desc2)
}

Saída

Desenhando retângulo com largura 4.0
e altura 2.0

Conclusão

A ocultação de tipo é uma técnica essencial para desenvolvedores Swift, especialmente ao lidar com protocolos que possuem tipos associados. Ao encapsular as implementações e fornecer uma interface uniforme, você pode escrever um código mais genérico e reutilizável. Esta aula abordou técnicas básicas e avançadas de ocultação de tipo, equipando você com o conhecimento para aplicá-las em seus próprios projetos.

Video

Did you like this article? Rate it from 1 to 5:

Thank you for voting!