Introdução
Neste capitulo, iremos abordar:
- Construtores
- Traits
Sempre no tom de levar a simplicidade e didática a este “blogbook”, se você ainda não viu o Capítulo 1, ainda há tempo de você clicar neste link e ver ou rever o básico da introdução da Linguagem.
Construtores
Construtores é um dos recursos mais importantes dentro da Orientação a Objetos, eles definem qual o “formato” inicial que um objeto terá, este formato, pode ser a inicialização de alguns atributos, ou mesmo toda a definição de um ou vários comportamentos (métodos).
Entendendo Classes vs Objetos
Uma das melhores explicações que eu aprendi para ensinar esta diferença as pessoas resume-se a abstração de uma: Receita e o Bolo! Parece engraçado, mas se você pensar, na receita estão definidos todos os atributos (quantidade de leite, trigo, ovos, essencias etc), bem como os métodos (leve ao forno, por X tempo , desenforme, cubra com algo). Neste caso, estamos dizendo então que a classe é nada mais que a receita, e os objetos são como os inúmeros bolos que podem ser construídos, a partir da receita.
Em Scala, você já pode definir um dos construtores a partir da declaração da classe:
package capitulo2
class Veiculo(marca:String, modelo:String) {
override def toString = marca.+(" , ").+(modelo)
}
Na classe acima, nós estamos definindo um construtor com 2 atributos String:
- Marca
- Modelo
Estes por sua vez são utilizados no método “sobrescrito”(override) toString. Na nossa classe capitulo2.Application você pode ver o funcionamento de nosso exemplo:
package capitulo2;
object Application {
var veiculo = new Veiculo("Ford","Marverick")
def main(args: Array[String]) {
Console.println("#############################");
Console.println(" Scala Tutorial = Capitulo 2 ");
Console.println("#############################");
Console.println(veiculo)
}
}
O Resultado é:
############################# Scala Tutorial = Capitulo 2 ############################# Ford , Marverick
Mais de um Construtor
Em inúmeras circunstâncias precisamos de mais de um construtor em uma classe, em Scala, nós pensamos mais em Construtores Auxiliares do que em uma método de construção totalmente diferente, imagine que na nossa classe Veiculo, agora nós queremos passar uma única um Integer como Marca e nada mais. Veja então abaixo a nova definição:
package capitulo2
class Veiculo(marca:String, modelo:String) {
def this(marcaId:Integer) = this( {if (marcaId == new Integer(1)) "Ford" else "Not Found"},
"Not Specified Model Yet" )
override def toString = marca.+(" , ").+(modelo)
}
Na instrução acima, nós somos sempre obrigados a invocar o construtor definido junto com a classe, mas veja que no caso acima, nós usamo o Inteiro(marcaId) para buscar um valor para o primeiro parametro (marca do tipo String) do construtor oficial. Uma vez isto alterado, vamos agora testar nossa classe:
object Application {
var veiculo1 = new Veiculo("Ford","Marverick")
var veiculo2 = new Veiculo(1)
def main(args: Array[String]) {
Console.println("#############################");
Console.println(" Scala Tutorial = Capitulo 2 ");
Console.println("#############################");
Console.println(veiculo1)
Console.println(veiculo2)
}
}
Veja o resultado que é exibido após a execução desta classe:
############################# Scala Tutorial = Capitulo 2 ############################# Ford , Marverick Ford , Not Specified Model Yet
Na saída de código, você vê o resultado da chamada diferente dos Construtores, neste caso, o oficial e o auxiliar.
Validando o Construtor
Quantas vezes em Java, C# ou outras linguagens devemos checar os valores dos atributos, em Scala, você tem como validar o seu construtor de forma bastante eficiente, observe as alterações feitas em nossa classe Veículo:
package capitulo2
class Veiculo(marca:String, modelo:String) {
require(marca!=null && modelo!="NIVA")
def this(marcaId:Integer) = this( {if (marcaId == new Integer(1)) "Ford" else "Not Found"},
"Not Specified Model Yet" )
override def toString = marca.+(" , ").+(modelo)
}
Com a instrução required, podemos controlar exatamente o que aceitamos ou não para a construção do objeto, neste caso, não podemos aceitar a marca como null e nem o modelo como Niva. Se testarmos nossa classe de teste capitulo2.Application:
object Application {
var veiculo1 = new Veiculo("Ford","Marverick")
var veiculo2 = new Veiculo(1)
var veiculo3 = new Veiculo(null,"NIVA");
def main(args: Array[String]) {
Console.println("#############################");
Console.println(" Scala Tutorial = Capitulo 2 ");
Console.println("#############################");
Console.println(veiculo1)
Console.println(veiculo2)
}
}
O resultado da execução será este:
Exception in thread "main" java.lang.ExceptionInInitializerError at capitulo2.Application.main(Application.scala) Caused by: java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:133) at capitulo2.Veiculo.(Veiculo.scala:5) at capitulo2.Application$.(Application.scala:9) at capitulo2.Application$.(Application.scala) ... 1 more
A mesma coisa aconteceria se você também tentasse desta forma construir o veiculo3:
var veiculo3 = new Veiculo("Ford","NIVA");
Traits
Para quem domina o inglês alguns termos fazem total sentido, sempre achei complexo ensinar o que uma Interface significa com esse nome, pois não significa algo de uma semantica tão lógica, já trait (traço, peculiariedade, feição característica) faz muito mais sentido. Pois bem, Traits são como Interfaces em Java ou C#, com uma diferença:
- Em Java, as Interfaces definem apenas métodos e não implementações, já nas Traits em Scala, você além da declaração pode ter também implementações.
Com base na informação acima, você pode se perguntar: “Ué, então lembra uma classe abstrata?”, a resposta é: Não! Pelo seguinte aspecto: Numa classe abstrata, você mantém o compromisso hierarquico, já numa Trait, você não precisa obedecer esse vínculo, ou seja, se você define uma estrutura de veículos, e você define um atributo do tipo Motor, lembre-se que não são apenas veículos que possuem Motores, ou você já viu alguém guardando um Liquidificador ou Motoserra no estacionamento do Shopping? Por mais que estas duas classes devam possuir o atributo Motor , elas não precisam herdar isto de Veículos , uma vez que elas podem implementar a Trait Motor . Isto gera um conceito bastante visto em linguagens como Ruby, conhecido como Mixings(Misturas).
Veja agora o exemplo de nossa Trait: Motor na seguinte porção de código:
package capitulo2
trait Motor {
var nome : String;
var combustivel: String;
def ligar();
def desligar();
}
Agora, vamos criar uma classe de veiculos Esportivos, para isso vamos extender a classe Veiculo “com” um Motor (Onde você leria extender X implementando y, pode ficar mais simples trocar o implementar pelo com):
package capitulo2
class Esportivo(marca:String,modelo:String) extends Veiculo(marca,modelo) with Motor {
override var combustivel= "FLEX"
override var nome="AP"
override def ligar() {
println( ".... Ligando Motor... wruuuunnnn.....")
}
override def desligar(){
println(".... Motor Desligado")
}
}
Observe que ao herdarmos a classe, temos que tomarmos cuidado com a questão de seu construtor como é visto acima, bem como realizar a sobrecarga ou sobrescrever (override) os métodos da nossa Trait Motor.
Veja nossa classe capitulo2.Application, adaptada para nosso exemplo:
object Application {
var veiculo1 = new Veiculo("Ford","Marverick")
var veiculo2 = new Veiculo(1)
var veiculo3 = new Esportivo("VOLKS","GOL");
def main(args: Array[String]) {
Console.println("#############################");
Console.println(" Scala Tutorial = Capitulo 2 ");
Console.println("#############################");
Console.println(veiculo1)
Console.println(veiculo3)
veiculo3 .ligar()
veiculo3.desligar()
}
}
Veja o output:
############################# Scala Tutorial = Capitulo 2 ############################# Ford , Marverick VOLKS , GOL .... Ligando Motor... wruuuunnnn..... .... Motor Desligado
Classes Abstratas
Em Scala, também existem classes abstratas, como em Java e C#, para definir uma classe como abstrata, você vai usar a mesma palavra reservada abstract, sua classe vai perder a chance de ser instanciada, e vai ser servir apenas como ponto de partida para suas derivações (filhos). Porém, neste caso, Classes abstratas e traits, como já foi dito, tem a grande diferença no que tange o “vínculo hierárquico”, nem sempre, você vai querer ou precisar deste vínculo, bem como, muitas vezes ele é incorreto. Se você quiser estabelecer um vínculo hierarquico, associado a um padrão de comportamento definido pela Trait, você pode criar uma classe abstrata que extenda a Trait, desta forma, você consegue trazer o comportamento e vinculo hierarquico, caso isto seja necessário.
Você também, consegue gerar herança entre Traits, como no exemplo abaixo:
package capitulo2
trait MotorEletrico extends Motor {
val voltagem_220: String = "220"
val voltagem_110: String = "110"
def carregar(voltagem:String) = {
if (voltagem eq voltagem_220) {
println("Carregando em 3 segundos...")
Thread.sleep(3000)
} else {
println("Carregando em 5 segundos...")
Thread.sleep(5000)
}
println("Carregado 100%");
}
}
Veja agora nosso carro Ecologico em Ecologico.scala:
package capitulo2
class Ecologico(marca:String,modelo:String) extends Veiculo(marca,modelo) with MotorEletrico {
override var combustivel= "Eletricidade"
override var nome="BD"
override def ligar() {
println( ".... Ligando Motor...zuuuuuumuuuuuuuu.....")
}
override def desligar(){
println("....dzzzz Motor Desligado")
}
}
Alterando nossa classe exemplo capitulo2.Application:
object Application {
var veiculo1 = new Veiculo("Ford","Marverick")
var veiculo2 = new Veiculo(1)
var veiculo3 = new Esportivo("VOLKS","GOL");
var veiculo4 = new Ecologico("TOYOTA","ECOCAR");
def main(args: Array[String]) {
Console.println("#############################");
Console.println(" Scala Tutorial = Capitulo 2 ");
Console.println("#############################");
Console.println(veiculo1)
Console.println(veiculo3)
Console.println(veiculo4)
veiculo3 .ligar()
veiculo3.desligar()
veiculo4.carregar("220");
}
}
O Resultado é o seguinte:
############################# Scala Tutorial = Capitulo 2 ############################# Ford , Marverick VOLKS , GOL TOYOTA , ECOCAR .... Ligando Motor... wruuuunnnn..... .... Motor Desligado Carregando em 3 segundos... Carregado 100%
Existem ainda vários outros recursos interessates no uso de Traits, principalmente para aqueles que gostam de criar DSLs (Domain Specific Languages) através de Fluent Interfaces, APIs que fazem com que os usuários possam sentir um real prazer em usá-las, por exemplo:
var application: Application = {
Configure.with.xml("rs.xml").reloadable(true).each(15).seconds
}
//ou
var intance: ProcessIntance = {
Engine.run(application).jbpm.name("RequestTravel").instance(id)
}
Por hora, acredito que o que vimos até aqui sobre este assunto, será suficiente para lhe ajudar no seu aprendizado com Scala.
Functions
Devido ao tamanho do capítulo 2, vamos mover Functions, e os motivos pelos quais podemos chamar Scala de uma linguagem funcional, para o próximo capítulo.
Como não é novidade, a máquina virtual Java não conhece a linguagem Java! Sim, ela conhece os bytecodes! E estes por sua vez podem ser gerados a partir de várias linguagens, entre elas: JavaScript, Ruby, Python, Groovy e Scala , este conceito é análogo ao CLR(Common Language Runtine) da Plataforma .Net . Linguagem de Programação é algo muitas vezes tão pessoal quanto seu time de futebol, eu tentei várias vezes usar Ruby, mas nada nele me encantou ou chamou tanto a atenção. Eu ainda consigo fazer qualquer coisa, desde atender meus clientes até extensões para controlar meu boxee e AppleTV da minha casa com Java, mas eu resolvi revisitar Scala mais uma vez, a primeira vez em 2009, não foi um contato que me fizesse investir algum tempo nela. E por que hora bolas eu estou começando o primeiro de vários posts sobre Scala? Simplesmente porque eu acredito que exitem potencialidades ainda não exploradas dentro da JVM, e estas são totalmente disponíveis para os programas feitos com Scala, e não somente Aplicações Web ou “Cool” Websites . Tais recursos veremos no decorrer do tempo que eu tenha para continuar esta série de tutoriais.
Como mencionei anteriormente, a primeira vez que vi Scala (2009), me deu medo, poucas vezes li algum código e não consegui entender nada! Como eu odeio videogames daqueles que se joga literalmente, resolvi pegar Scala como um “game” a ser “zerado”, e o resultado das fases deste jogo, eu irei publicar aqui, para ajudar pessoas a não terem o mesmo trauma e susto que eu tive. Esta série de tutoriais, que tomei a iniciativa de começar pra mim é também uma das maneiras mais prazerosas de aprender: Compartilhando conhecimento. Mas se você quiser contribuir de alguma forma com este espaço, não hesite em me contacatar @jedgarsilva.
