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étododesenhar
. - O inicializador recebe qualquer tipo que conforma a
Desenhavel
e extrai seu métododesenhar
. - O método
desenhar()
deQualquerDesenhavel
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
- Flexibilidade: A ocultação de tipo permite que você trabalhe com vários tipos de maneira uniforme, tornando seu código mais flexível.
- Abstração: Você pode definir interfaces sem se preocupar com as implementações subjacentes.
- 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.