Scala: Stackable Modifications com Traits

Scala: Stackable Modifications com Traits

Se você é programador Java pode imaginar que Traits são como herança múltipla ou mesmo meras interfaces com default methods mas, existe uma diferença fundamental que diferencia os Traits destas duas abordagens: Veja o exemplo.

Supondo que nossa tarefa seja implementar a seguinte classe abstrata:

abstract class Greetings {

  def sayHello(name: String): String

}

Criamos então a classe abaixo:

class BasicGretings extends Greetings{

  override def sayHello(name: String): String = s"hello $name"

}

Agora vamos criar um Trait que também implementa a classe abstrata Greetings:

Veja que ele chama o método da superclasse e adiciona uma exclamação no final.

trait Exclamation extends Greetings {

  abstract override def sayHello(name: String) = super.sayHello(name) + " !!!!!!"

}

Vamos ainda criar mais um Trait que implementa a classe Greetings. Este converte tudo para maiúsculas

trait Uppercase extends Greetings {

  abstract override def sayHello(name: String) = super.sayHello(name).toUpperCase

}

Agora vamos criar uma classe que além de estender BasicGretting adiciona os 2 Trais

class MegaGreetings extends BasicGretings with Uppercase with Exclamation

Como vimos as classes BasicGretings, Uppercase e Exclamation implementam o método sayHello ao mesmo tempo.

O que acontecera?

1 – Vai prevalecer o método da classe concreta
2 – Não compila (diamond of death)
3 – Todos os métodos serão chamados
4 – Somente o método do último trait

Vejamos

resultado

Sim ele vai chamar todos métodos! O da classe concreta e o método de cada trait em cadeia. Isto se chama Stackable Trait Pattern. Podemos usa-lo para adicionar um comportamento de forma totalmente modular.

Veja que eu não precisaria ter criado a classe MegaGreetings que estende de BasicGretings. Basta eu usar a seguinte sintaxe:

Somente Basic:

scala> val basic1 = new BasicGretings()
scala> basic1.sayHello("World")
res6: String = hello World

Basic com exclamação:

scala> val basic2 = new BasicGretings() with Exclamation
basic2: com.example.BasicGretings with com.example.Exclamation = $anon$1@2cd526ba

scala> basic2.sayHello("World")
res7: String = hello World !!!!!!

Basic com exclamação e maiúsculas:

scala> val basic3 = new BasicGretings() with Exclamation with Uppercase
basic3: com.example.BasicGretings with com.example.Exclamation with com.example.Uppercase = $anon$1@b6a6d85

scala> basic3.sayHello("World")
res8: String = HELLO WORLD !!!!!!

Veja que eu consigo compor o comportamento do meu objeto no momento de instância-lo adicionando e removendo Trais com a palavra with e sem precisar adicionar código na classe BasicGretings. Repare que a implementação no trait chama o super. O que este método faz é desconhecido no momento da criação do Trait. O “bind” é feito dinamicamente.

Essa é umas das coisas que podemos fazer com Trais. Eles são estruturas fundamentais para reutilização de código no Scala. No próximo artigo vou falar um pouco sobre Rich Interfaces.

abcs

One comment

Leave a Comment

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *