OBJETOS, CLASSES E MÉTODOS 83 Esta sintaxe também é válida no caso em que existe encadeamento de objetos, uma vez que dentro de um objeto podem existir outros objetos. Nesse caso, continuam a usar-se pontos para separar o objeto do objeto que este contém e da variável dentro deste: Nome_do_Objeto.Variavel-Objeto.Variavel; 6.3.2 OBJETOS E MÉTODOS Os métodos são referenciados por um objeto de uma forma muito idêntica à que é usada para referenciar as variáveis de objeto: utilizando os pontos. A diferença reside nos argumentos que os métodos podem aceitar. A sintaxe completa é a seguinte: Nome_do_Objeto.Metodo(Arg1, Arg2,...,ArgN); Esta sintaxe pode aparecer de várias maneiras. Um método pode não ter argumentos: v1.ligar_motor(); ou pode devolver, ele próprio, um método: v1.metodo1().metodo2(); ou ainda ser chamado um método que pertença a um objeto, que pertence ao objeto em causa: v1.variavel-objeto.metodo(); Um exemplo muito claro desta sintaxe, embora aplicada a classes e variáveis de classe, em vez de objetos e variáveis de objeto, é um método que o leitor já tem utilizado bastante ao longo do livro: o System.out.println(arg). “System” é o nome de uma classe e “System.out” é uma variável de classe. Esta variável contém um objeto, que tem um método chamado println, que envia a string que lhe for passada como argumento para o ecrã. 6.3.3 EXEMPLO Vejamos um exemplo de como criar uma classe e operar com objetos criados nesta classe. Para tal, vamos considerar uma classe “Computador” e definir algumas características: class Computador { /* Variaveis de Objecto */ final static boolean ligado = true; final static boolean desligado = false; String marca; © FCA – Editora de Informática OBJETOS, CLASSES E MÉTODOS 95 class Veiculo { void travar() { System.out.println(“Carregar com o pe direito no pedal do meio...”); } } Agora, proceda-se à criação de um novo ficheiro, com a subclasse “Bicicleta”: Ficheiro “Bicicleta.java” class Bicicleta extends Veiculo { // Override do metodo void travar() { System.out.println(“Apertar o manipulo com a mao direita...”); } public static void main( String[] args) { Veiculo v = new Bicicleta(); v.travar(); } } Neste caso, a classe “Veiculo” implementa um método travar. O autor deste método não pensou certamente na especificidade de alguns veículos quando o construiu e, assim, ao utilizar uma subclasse “Bicicleta”, da classe “Veiculo”, faz-se o override do método travar, por forma a adequar o código do método às características do tipo de objetos a criar nesta classe. No caso de o método travar ser chamado num objeto concretizado na classe “Bicicleta”, vai ser este último a ser chamado e não o definido na superclasse “Veiculo”, como aconteceria se não fosse feito o override. Compilando ambos os ficheiros e executando o “Bicicleta.class”, obtém-se um resultado óbvio (Figura 6.8). FIGURA 6.8 – Execução do exemplo com override O método travar() que foi chamado foi o reescrito na classe “Bicicleta”. © FCA – Editora de Informática 134 PROGRAMAÇÃO EM JAVA – CURSO COMPLETO TimesRoman, Courier, Terminal, Helvetica, Dialog e Symbol); e Estilo_da_Font é uma variável que representa os tipos de formatações de texto adicionais que gostamos de dar aos nossos textos, por exemplo, realçando as palavras a negrito (bold) ou a itálico. A lista completa está definida na classe “font”, mas os mais populares estilos são “Font.PLAIN”, “Font.BOLD” e “Font.ITALIC”. FIGURA 7.26 – Variantes de texto Finalmente, temos também representado o tamanho, em pontos, da letra a utilizar. São vulgares valores entre 8 e 24 pontos para texto normal, mas o leitor pode alterar estes parâmetros à vontade. A seguir à declaração do objeto na classe “Font”, é necessário utilizar um método chamado setFont() para esta ação ser aplicada ao objeto da classe “Graphics” que estiver a ser utilizado. Fazendo uma breve demonstração de utilização, pode dar-se o seguinte exemplo: /* Applet de demonstracao de Fonts */ package pac; import java.awt.Graphics; import java.awt.Font; public class TesteApplet extends java.applet.Applet { public void paint(Graphics elemento) { /* Declaracao das Fonts */ Font f = new Font("TimesRoman", Font.PLAIN, 12); Font f1 = new Font("TimesRoman", Font.ITALIC, 12); Font f2 = new Font("Courier", Font.BOLD, 24); elemento.setFont(f); © FCA – Editora de Informática 182 PROGRAMAÇÃO EM JAVA – CURSO COMPLETO Voce Pressionou a tecla ? Voce Pressionou a tecla A Neste exemplo, a tradução do código da tecla shift para char é o “?” e o caráter virtual que aparece em seguida já é o “A”, em vez do “a”. Na especificação Java API da classe “KeyEvent”, aparece uma lista enorme de variáveis estáticas que representam carateres especiais (já usámos duas delas no exemplo anterior de tradução das setas esquerda e direita). Por exemplo (entre muitos outros): VK_ALT Tecla Alt VK_CAPS_LOCK Caps Lock VK_ESCAPE Esc VK_AT @ VK_CONTROL Control VK_SHIFT Shift Um exemplo muito simples de uma aplicação deste tipo de variáveis no teste de pressão de uma tecla especial pode ser o seguinte: import java.awt.*; import java.awt.event.*; import java.applet.*; public class TesteKey2 extends Applet implements KeyListener { public void init() { requestFocus(); addKeyListener(this); } public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_CONTROL) System.out.println("Voce pressionou o caracter Control, com o codigo ASCII " + e.getKeyCode()); else System.out.println("Voce pressionou " + e.getKeyChar()); } public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e) {} © FCA – Editora de Informática 210 PROGRAMAÇÃO EM JAVA – CURSO COMPLETO carta1.add(new Button("Botao3 (1)")); carta1.add(new Button("Botao4 (1)")); /* Painel 2 - Definir Layout e inserir objectos */ carta2.setLayout(new FlowLayout()); carta2.add(new Button("Botao1 (2)")); carta2.add(new Button("Botao2 (2)")); carta2.add(new Button("Botao3 (2)")); carta2.add(new Button("Botao4 (2)")); /* Painel 3 - Definir Layout e inserir objectos */ carta3.setLayout(new BorderLayout()); carta3.add("North", new Button("Botao1 (3)")); carta3.add("South", new Button("Botao2 (3)")); carta3.add("East", new Button("Botao3 (3)")); carta3.add("West", new Button("Botao4 (3)")); add(“Cartas”,cartas); /* Adicionar painel principal */ cartas.add(carta1); /* Adicionar painel 1 ao principal */ cartas.add(carta2); /* Adicionar painel 2 ao principal */ cartas.add(carta3); /* Adicionar painel 3 ao principal */ } } Na Figura 9.12 nota-se bem a diferença entre estes três layouts. FIGURA 9.12 – Vários layouts © FCA – Editora de Informática 270 PROGRAMAÇÃO EM JAVA – CURSO COMPLETO passo = 1; // Voltar demonstracao ao principio } else { saida = "Erro."; // Esta mensagem nao devera aparecer } } return saida; } } O protocolo que se pretende é algo como o seguinte: Servidor: Ola. Identifica-te! Cliente: Eu sou o Pedro. Servidor: A senha e: "Azul". Qual e a contra-senha? Cliente: Amarelo. Servidor: Autenticacao valida! Ola Pedro. O codigo de hoje e: 7811 Cliente: Adeus. Servidor: Adeus Pedro! Se o leitor executar o servidor, e posteriormente o cliente, poderá então escrever na janela do cliente e procurar seguir o protocolo. Foram introduzidas algumas ajudas ao protocolo, que aparecem quando o utilizador está perdido. Neste exemplo (Figura 10.3), o cliente e o servidor são entidades separadas, comunicando uma com a outra por TCP/IP. Poderiam estar facilmente localizados em máquinas diferentes, acessíveis via Internet, bastando para tal trocar o “localhost” pelo respetivo endereço IP. FIGURA 10.3 – Execução de exemplo cliente-servidor © FCA – Editora de Informática ARQUITETURA DE APLICAÇÕES JAVA 307 Um exemplo muito concreto para ajudar o leitor a perceber os conceitos de separação de apresentação da lógica funcional é o seguinte: imagine que pretende criar uma aplicação Java muito simples, que vá buscar um conjunto de valores a uma tabela de uma base de dados e apresente a soma dos seus valores. Com o que já aprendeu ao longo do livro, o leitor poderá facilmente construir um programa que faça isto. Nas Figuras 12.4 e 12.5 procedemos à criação de uma base de dados de testes, neste caso em mySQL. Neste exemplo utilizamos uma única tabela, contendo um identificador de registo e uma parcela, registando um valor em cada registo distinto. Começamos por criar a estrutura de dados, composta pelas colunas “id” e “parcelas”, ambas de tipo integer. Em sequência, introduzimos alguns dados na tabela. FIGURA 12.4 – Criação de uma estrutura de dados (1) FIGURA 12.5 – Criação de uma estrutura de dados (2) A soma dos registos da coluna “parcelas” é 36, sendo este o valor que pretendemos atingir com o nosso programa. Nesta primeira versão temos um programa Java que se liga à base de dados, calcula o valor e o devolve: package pac; import java.sql.*; import java.util.*; public class Teste { © FCA – Editora de Informática 13 SERVLETS Como já tivemos ocasião de descrever, as servlets são programas Java compilados e que são executados do lado do servidor. As servlets são parte importantíssima da maioria das frameworks de desenvolvimento Java e uma das peças da tecnologia JEE, pelo que neste capítulo procuraremos descrever com algum pormenor a forma como podem ser construídas, instaladas e executadas, bem como identificar as circunstâncias em que devem ser utilizadas. 13.1 INTRODUÇÃO As servlets funcionam num modelo de pedido/resposta, como muitos outros objetos em utilização na Web. O cliente efetua um pedido (habitualmente HTTP) que invoca a servlet no servidor e depois recebe como retorno o resultado da sua execução (Figura 13.1). Web container Browser Servidor Web Servlet Conteúdo estático Base de Dados FIGURA 13.1 – Execução de uma servlet O servidor Web tradicional continua a poder servir conteúdo estático ou dinâmico, mas é complementado com uma nova entidade lógica: o Web container (contentor de componentes Web), uma peça JEE que até pode funcionar na mesma máquina em que o servidor Web se situa. Este processo funciona bem, mas surge à partida uma questão de fundo: numa aplicação de qualquer tipo, é suposto que o cliente seja mantido num determinado contexto de sessão, ou seja, é expectável que as respostas que a aplicação Web lhe dá sejam dependentes de vários fatores, como o seu perfil de utilizador, as escolhas que já introduziu ou o percurso que já efetuou no site. Neste pressuposto (indispensável em aplicações Web © FCA – Editora de Informática 356 PROGRAMAÇÃO EM JAVA – CURSO COMPLETO Uma JSP implementa-se estendendo uma classe chamada “HttpJspBase” que, por sua vez, implementa a interface Servlet. Há dois métodos essenciais envolvidos na execução de uma JSP: jspinit() – Executado quando a JSP é inicializada, análoga ao método init() das servlets; jspdestroy() – Executado quando a JSP é terminada, comparável ao método destroy() das servlets. Um outro método é gerado pelo contentor de servlets na compilação da JSP, designado por jspservice(), o equivalente do método service() das servlets. Este método irá conter o código principal da JSP, tratando de gerir os pedidos e as respostas. Falando de arquiteturas, as primeiras aproximações a este tema por parte da Sun falavam em dois modelos para utilização de JSP: o modelo 1 e o modelo 2. O modelo 1 baseava-se na utilização de JSP com recurso a EJB para interagir com os dados (Figura 14.4). Pedido JSP Resposta EJB Dados Browser FIGURA 14.4 – Modelo 1 de utilização de JSP Este modelo apresenta alguns problemas, sendo o principal a inexistência de separação entre a apresentação e a lógica, porque essa função está toda concentrada nas JSP (as EJB são utilizadas para fazer interface com os dados). Recomendava-se, portanto, o recurso ao chamado modelo 2, já falado por ser conhecido como MVC (Figura 14.5). Pedido Controller servlet EJB Dados Resposta View JSP Browser FIGURA 14.5 – Modelo 2 de utilização de JSP © FCA – Editora de Informática JA V A 8 491 Com lambda: public class execucao { public static void main(String[] args) { System.out.println(“Teste”); Runnable r = () -> System.out.println(“Ola Mundo”); r.run(); } } Repare-se na forma compacta como esta expressão transforma cinco linhas de código numa só. O código fica, sem dúvida, mais sucinto e fácil de ler. Uma expressão lambda pode ou não ter parâmetros, e se os tiver pode ter vários. Por outro lado, o tipo de parâmetros pode ser declarado ou omitido (expressões como (int x, int y) podem ser substituídas por (x,y), sendo o tipo derivado do contexto). Outro exemplo de utilização de uma expressão lambda é o da instrução seguinte, onde inicializamos um thread apenas com uma linha: new Thread( () -> System.out.println(“Ola Mundo”) ).start(); Ou, ainda, o exemplo seguinte de uma sintaxe de gestão de eventos de um botão, utilizando uma expressão lambda: button.AddActionListener( (ev) -> { System.out.println(“Botao carregado”); }); 21.2 INTERFACES FUNCIONAIS Tecnicamente, designa-se por interface funcional uma interface em que é declarado apenas um método abstrato. Podemos encontrar vários exemplos em Java de interfaces funcionais, como é o caso da ActionListener, mas o que surge de novo no Java 8 é a possibilidade de, através de uma expressão lambda, instanciar objetos de forma muito simplificada. Um exemplo de algo deste tipo foi apresentado na secção anterior: Runnable r = () -> System.out.println(“Ola Mundo”); neste caso, em relação à interface functional java.lang.Runnable. No Java 8 criou-se uma forma de identificar as interfaces funcionais, designandoas da seguinte forma: @FunctionalInterface public interface AMinhaInterface { public void executar(); } © FCA – Editora de Informática