Mostrando postagens com marcador Java. Mostrar todas as postagens
Mostrando postagens com marcador Java. Mostrar todas as postagens

segunda-feira, 24 de agosto de 2009

JSP e Oracle - Para apresentar uma Treeview

Olá pessoal!

Dando manutenção em um sistema java web com interface jsp precisei usar uma treeview para apresentar as categorias de produtos para o usuário. Vou relatar aqui a experiência.


As categorias estão modeladas no banco em uma tabela com autorelacionamento.



No oracle para consultar uma table com autorelacionamento podemos utilizar a seguinte query:


select id, LEVEL, SYS_CONNECT_BY_PATH(nome, '@') as caminho
from categoria CONNECT BY parent_id = PRIOR id START WITH id = categoria_inicial


A categoria_inicial é a primeira categoria de uma árvore, nesse sistemas existem várias árvores de categorias.

O resultado fica assim para a categoria_inicial igual a 30:

id level caminho
30 1 @Material de escritório
31 2 @Material de escritório@Informática
34 3 @Material de escritório@Informática@Tinta
55 4 @Material de escritório@Informática@Tinta@Tinta Impressoras
60 3 @Material de escritório@Informática@Armazenamento
63 4 @Material de escritório@Informática@Armazenamento@DAT/DLT/DVD/DDS
64 4 @Material de escritório@Informática@Armazenamento@Disquetes
92 3 @Material de escritório@Informática@Teste
93 4 @Material de escritório@Informática@Teste@Teste1
113 4 @Material de escritório@Informática@Teste@Teste2
120 4 @Material de escritório@Informática@Teste@Test3

Ai no java criei uma classe para representar a estrutura da categoria, ficou assim:

public class CategoriaTreeView {
public String id;
public int level;
public String path;

public CategoriaTreeView(String id, int level, String path){
this.id = id;
this.level = level;
this.path = path;
}
}


Como essa classe vai ser utilizada somente como uma estrutura de dados para representar o dado que será exibido na tela ela não tem gets e sets. Nem toda classe java precisa ter gets e sets. Gets e sets aqui são desnecessários e não acresentam nada. Acredite. Mas isso é assunto para outro post.

Também tenho um DAO que acessa o banco e entrega um List com os objetos CategoriaTreeView.

Antes disso fiz uma pesquisa na internet sobre como criar uma treeview no jsp (ou html) e encontrei o jQuery plugin: Treeview que transforma uma lista não ordenada do html <ul> em uma árvore.

Agora o problema é transformar a minha coleção de CategoriaTreeView em uma lista não ordenada com <ul> e <li>. Para isso eu criei a seguinte função recursiva que retorna uma String que será utilizada dentro do html:


private String processa(int atual, List<CategoriaTreeView> lista){
if(lista == null) return "";
String out = "";
if(lista.size() == 0) {
if(atual > 0){
out += "</li>\n";
out += "</ul>\n";
out += processa(atual - 1, lista);
}
}else if(lista.size()>0){
CategoriaTreeView item = lista.remove(0);
if(item.level == atual){
out += "</li>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level > atual){
out += "<ul>\n";
out += "<li><span>" + subString(item.level, item.path) + "</span>\n";
out += processa(item.level, lista);
}else if(item.level < atual){
out += "</li>\n";
out += "</ul>\n";
// adiciono o cara de volta na lista pois ainda não foi processado. estou voltando um nivel na árvore.
lista.add(0, item);
out += processa(atual - 1, lista);
}
}
return out;
}

Também temos a função para retornar a categoria de dentro do caminho:


private String subString(int i, String s){
String[] ss = s.split("@");
return ss[i];
}


Dentro do meu servlet eu tenho o seguinte código:

ArrayList categorias = dao.categorias(categoria_inicial);
String treeView = processa(0, categorias);
treeView = treeView.replaceFirst("<ul>", "<ul id=\"browser\">");
request.setAttribute("treeView", treeView);

Para exibir a treeview no jsp eu utilizei o exemplo simple.html que vem no download do jQuery plugin: Treeview. A única mudança foi que eu fiz o download do jquery ao invés de usar o link direto do ajax.googleapis.com.

Adicionei o seguinte ao jsp:


<link rel="stylesheet" href="../jquery.treeview.css" />
<link rel="stylesheet" href="../red-treeview.css" />
<link rel="stylesheet" href="screen.css" />

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script src="../lib/jquery.cookie.js" type="text/javascript"></script>
<script src="../jquery.treeview.js" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function(){
$("#browser").treeview({control: "#treecontrol", animated:"normal", persist: "cookie"});
});
</script>

<%
String s = (String)request.getAttribute("treeView");
if(s != null && !s.trim().equals("")){
%>
<tr>
<td>
<br>
<div id="treecontrol">
<a title="Collapse the entire tree below" href="#">Fechar Tudo</a>
<a title="Expand the entire tree below" href="#">Abrir Tudo</a>
</div>

</td>
</tr>
<tr>
<td>
<br>
<div><%= s %></div>
</td>
</tr>
<%
}
%>


O resultado fica parecido com esse demo que está no site.



Abraços, Rodrigo Alencar.

Artigo completo (View Full Post)

domingo, 5 de outubro de 2008

Java - Declarações e Modificadores de Classes - Declaração para Arquivos-Fontes

Os modificadores se dividem em duas categorias: “Modificadores de acesso” e “Modificadores que não se referem a acesso”.

1) Modificadores de acesso

Servem para você poder restringir ou permitir acesso a uma classe que você está criando (ou partes dessa classe). Ou seja, definem o escopo de visivilidade de uma classe. Os escopos devisibilidade definido pelos modificadores de acesso são: Público, Protegido e Privado.
Eles são definidos em código através do emprego das palavras reservadas: “public” (Escopo de visibilidade público), protected (Escopo de visibilidade protegido), private (Escopo de visibilidade privado).
É importante notar que, embora existam quatro controles de acesso (que funcionam como níveis de acesso), os modificadores de acesso são apenas três (public, protected, private). O quarto nível de controle de acesso (chamado de acesso “default” ou "de pacote") é o que você obtém quando não usa nenhum dos três modificadores de acesso na declaração realizada durante a codificação de uma classe. Ou seja, toda classe, método, ou/e variável de instância que você declarar possui um controle de acesso, independentemente disso ser declarado explicitamente ou não.
Todos os quatro controles de acesso são adequados para as declarações de métodos e variáveis. Contudo, para classses, somente dois deles são válidos: público ou default . Uma classe só pode ser declarada como pública ou default, os outros dois níveis de controle de acesso não se aplicam para classes.
Os modificadores de acesso são os responsáveis por outra característica fundamental para a O.O. o “encapsulamento

1.1) Acesso a Classes

O termo aceeso a classes refere-se ao fenômeno que através de um método próprio, uma classe (classe “ZnX”) acessar outra (classe “ZnY”). Isso significa que a classe “ZnX” pode fazer uma das seguintes coisas:
1) Criar uma instancia da classe “ZnY”.
2) Estender a classe “ZnY” (ou seja, tornar-se uma subclasse da classe “ZnY”).
3) Acessar certos métodos e variáveis dentro da classe “ZnY”, dependendo do controle de acesso desses métodos e variáveis.


Definindo Controle de Acesso em Classes

Na prática, acesso significa visibilidade. Suponha que temos duas classes: classe “ZnX” e classe “ZnY”. Se a classe “ZnX” não puder ver a classe “ZnY”, o nível de acesso dos métodos e variáveis dentro da classe “ZnY” não fará diferença. A classe“ZnX” não terá como acessar os métodos e propriedades de “ZnY”.

Acesso Default: Uma classe cujo modificador de acesso é o chamado “default”, é a quela que não tem nenhum modificador precedendo na sua declaração. Esse é o controle de acesso que você obtém quando não digita um modificador na declaração da classe. Pense no acesso defaultcomo um acesso de nível de pacote, porque a classe com acesso default só pode ser vista por classes de dentro do mesmo pacote. Por exemplo: Se a classe “ZnX” e a classe “ZnY” estiverem em pacotes diferentes, e a classe “ZnX” tiver acesso default, a classe “ZnY” não será capaz de criar uma instância da classe “ZnX”. Nem mesmo, se quer, declarar uma variável ou tipo de retorno da classe “ZnX”. Fataliticamente, para a classe “ZnY” a classe “ZnX” nem sequer existe. Do contrário, o compilador irá reclamar caso isso não seja repeitado. Observe o seguinte arquivo-fonte:



package fermentadosZN;

class VinhoZn { }


Agora observe o segundo arquivo-fonte:

package destiladosZN;

import fermentadosZN.VinhoZn;

class ConhacZn extends VinhoZn { }


Observe, nos trechos de código ilustrados acima que, a superclasse “VinhoZn” está em um pacote diferente da subclasse “ConhacZn”. Veja na linha 3 a declaração “import” possibilitando a package “destiladosZN” importar a classe “VinhoZn” para a ser usado n apackage “destiladosZN”. Supondo que tentássemos compilar, o arquivo “fermentadosZN” compilará sem problemas, contudo, quando tentamos compilar o arquivo “destiladosZN”, receberemos uma mensagem de exceção semelhante do tipo:



Can't access class destiladosZN. Class or interface must be public, in same package,or an
accessible member class.
import destiladosZN;


“destiladosZN” não compila porque a sua superclasse, “VinhoZn”, tem acesso default e está em um pacote diferente. Existem duas coisas que podemos pode fazer para nosso problema hipotético:

1) Poderiamos colocar ambas as classes no mesmo pacote,
2) Ou. poderiamos declarar “VinhoZn” como public. Exemplo:


Esse tipo de situação/problema costuma ser usado em prova de certificação. Portanto, quando você vir uma questão com lógica complexa, certifique-se de olhar os modificadores de acesso antes de qualquer coisa. Assim, caso identifique uma violação de acesso (por exemplo, uma classe do pacote “X” tentando acessar uma classe default do pacote “Y”), você saberá que o código não vai compilar, portanto não precisa nem se dar ao trabalho de tentar entender a suposta lógica complexa da questão. A qual está lá justamente para desviar sua atenção indizindo você ao erro. Além de economizar tempo e stress.

Acesso Público: Uma declaração de classe com a palavra reservada public torna ela visivél a todas as classes, de todos os pacotes. Todas as classes do Universo Java (JU) têm acesso a uma classe pública. Contudo, não se esqueça que mesmo sendo pública, uma classe para ser usada, se estiver em um pacote diferente, será obrigatório importar-lá.


2) Outros Modificadores de Classes (Não-referentes a Acesso)

Além dos modificadores vistos anteriormente ainda existem mais três, os quais são definidos pelas palavras reservadas “final”, “abstract” e “strictfp”. Esses modificadores existem em adição a qualquer controle de acesso existente na classe. Logo poderiamos, por exemplo, declarar uma classe como “public” e “final” ao mesmo tempo.
Todavia, isso não é adequado para todas as situações. Não é sempre que podemos misturar modificadores não-referentes a acesso. Por exemplo: É possível usar “strictfp” em combinação com “final”, contudo nunca (jamais, em tempo algum) marcar uma classe como “final” e “abstract” ao mesmo tempo.
Imagino que isso possa parecer óbvio demais para quem já conhece bem orientação a objetos. Entretando, muitos aprendem java sem necessáriamente aprofundar sobre OO. Quase sempre por isso, sentirá dificuldade em aprender e aplicar certos pontos sobre Java que estiver nesta situação.

Vejamos então sobre estes últimos modificadores ....

strictfp”: Palavra reservada que pode ser usada para modificar uma classeou um método, mas nunca uma variável. Marcar uma classe como “strictfp” significa que qualquer código de método na classe será compatível com às regras do padrão IEEE 754 para pontos flutuantes. Sem esse modificador, os pontos flutuantes usados nos métodos poderão se comportar de forma variante conforme a plataforma. Se não declarar a classe como strictfp, ainda assim você poderá obter um comportamento strictfp para métodos específicos, declarando o método como strictfp.

final”: Define as “Classes Finais” - a palavra-chave “final” significa que a classe em questão não pode ser subclassificada. Ou seja não pode ser estendida, herdada por nenhuma outra. Nenhuma outra classe jamais poderá estender uma classe final. Caso alguém tente fazê-Io receberá um erro de compilação.
Tenha cuiadado ao usar esse tipo de modificados, você só deve marcar uma classe como final se possuir certeza absoluta de que numca vai precisar especializá-la. Nunca nenhum dos métodos dessa classe jamais vai ser sobrescrito.
Por que, então, precisamos marcar uma classe como “final”. Visto que, isso restringe aplicação do conceito de herança presente nas linguagens orientadas a objetos? Suponhamos que o comportamento de sua classe seja profundamente dependente da implementação de certos métodos. Por isso você considere que se esses, certos, métodos forem alterados seja impossível garantir um comportamento adequado a classe. Logo, marcá-la como “final” lhe dará a segurança de que ninguém poderá modificar a implementação dos mesmos sem você saber.
Note que muitas classes das bibliotecas fundamentais Java são declaradas como “final”. Por exemplo, a classe String não pode ser estendida. Não é difícil considerar os riscos caso você não pudesse garantir a forma como um objeto String funcionaria em qualquer sistema que executasse a sua aplicação. Você concorda comigo que, se os programadores tivessem a liberdade de estender a classe String (e assim colocar as suas novas instâncias da subclasse String onde esperam-se instâncias de java.lang.String), dar manutenção em muitos sistemas Java seria a principal causa dos picicóticos maniácos depressivos internados nos centros psquiátricos da vida?
Portanto, use final para segurança, mas apenas quando tiver certeza de que a sua classe final de fato já disse tudo o que precisa ser dito nos seus métodos. Marcar uma classe como final significa, na prática,que a sua classe nunca será especializada para uso mais específico.

Asseguir vamos modificar nosso exemplo anterior colocando a palavra reservada “final” na declaração:

package fermentadosZN;

public final class VinhoZn {

public void fermentar(){}
}


Ok, supondo que tentassemos compilar a subclasse ConhacZn:


package destiladosZN;

import fermentadosZN.VinhoZn;

class ConhacZn extends VinhoZn { }


Então, receberemos um erro tipo:

Can't subclass final classes: class
fermentadosZN.VinhoZn class ConhacZn extends VinhoZn{
1 error}


OBS:
É de extrema importância entender que marcar uma classe como “final” elimina um benefício fundamental da orientação a objeto, a estensibilidade (herança). No dia-a-dia, tipo vida real, você raramente precisará criar uma classe final. Portanto, exceto que você tenha uma séria e justificada razão, presuma sempre que algum dia, em algum momento, outro desenvolvedor poderá precisar estender a sua classe.

abstract: Palavra reservado para marcar classes como “Abstratas”. Uma classe marcada com “abstract” não pode ser instanciada nunca. Isso é a primeira coisa mais importante que você precisa saber sobre classes abstratas. A segunda coisa mais importante sobre elas é que, o seu único propósito, sua principal missão no universo, é ser estendida (Herdada, especialisada, em algumas literaturas encontraremos o termo “subclassificada”). Imagino que alguém possa estar se perguntando: Se posso fazer herança a partir de qualquer classe (exceto as marcadas como “final”), por que preciso de uma classe abstrata? A resposta consiste na mesma idéia envolvida quando, por exemplo, ao nos referirmos sobre um determinado veículo o fazemos usando o termo "Automóvel".
Uma classe abstrata pode ser executada, mas não podemos criar uma instância dela. Caso essa explicação tenha deixado dúvidas procure ler outros artigos onde eu e Felipe explicamos sobre herança.

Outras questões sobre classes abstratas

Repare que você pode compilar e executar uma classe abstrata, desde que não tente criar uma instância dela. Por que criar uma classe se você não pode criar (instanciar) objetos dela? Antes de respondermos, gostaria de chamar a atenção que este entendimento é um elemento chave para quem pretende usar OO em seus projetos. Não acho fácil responder essa pergunta, mesmo assim tentarei apresentar uma linha de raciocínio que possa trazer mais luz sobre essa questão.
Pois bem, prossigamos: Considere um fenômeno comum o qual aplicamos recorrente mente no cotidiano em diversas situações. Esse fenômeno a que me refiro, consiste na capacidade que temos de abstrair ou especializar significados quando estamos nos relacionando com o mundo exterior: Ao tentarmos comunicar alguma mensagem, ou quando estamos do outro lado, interpretando um conteúdo comunicado, ou quando estamos construindo uma idéia sobre alguma coisa e precisamos fazer avaliações e comparações. Entendo que o grande benefício da utilização de classes abstratas, é permitir que possamos “importar” essa flexibilização para perceber significados, usada nos processos cognitivos (construção e interpretação de informações) para a computação (especificamente na construção de programas).
Analisemos uma situação hipotética, um exemplo: Num dado momento ao falar sobre música, uma pessoa, usa o termo “composições” para abstrair detalhes sobre autor, estilo, ou versão:

“Gostaria de conhecer mais sobre as composições musicais no século passado”.

Esse tipo de construção permitiu um grau de abstração grande sobre o significado “Música”. Isso lhe foi bastante útil porque ela poder expressar de forma eficaz seu desejo em conhecer qualquer estilo de música que tenha sido composta no século passado. Entretanto, se ela falar especificamente numa música o termo genérico não encontra significância. Ou seja, não é possível apresentar nenhum exemplo de música onde os detalhes sobre o estilo, gênero, autor, versão sejam ausentes. Por exemplo, em resposta a pergunta sobre uma música que atenda o critério de “composição do século passado” alguém cante “Born to Be Wild”, a resposta traz intrínseca as informações sobre os detalhes que a identificam univocamente como tal.

Outro exemplo, supondo que alguém cite genericamente o significado “veículo”. Logo, podemos presumir podermos contar com alguma outras coisas (atributos e ações), genéricas, comuns a todos os veículos. Como no mundo real não conseguimos encontrar um exemplo qualquer de veículo, pois, seguindo o raciocínio anterior, ao citar o exemplo pedido imediatamente os detalhes sobre ele se revelam exaurindo a generalização embutida na palavra “veículo”, trazendo a existência uma instância detalhada do significado pedido. Portanto, da mesma forma quando programando, definimos uma classe “Veiculo” ela não deve permitir ser instanciada. Pois, definitivamente não desejamos que alguém de fato crie um objeto “Veiculo” genérico. Caso isso não fosse respeitado o primeiro e principal problema encontrado é justamente que o mecanismo de generalização descrito na parágrafo anterior seria perdido. Conseqüentemente teríamos alguns problemas: Como inicializar o seu estado deste objeto “Veiculo”? De que cor ele seria? Quantos assentos? Potência do motor? Direção hidráulica ou não? Ainda, de que forma ele se comportaria? Como os métodos seriam implementados?
Isso demandaria um esforço considerável, o que tornaria o desenvolvimento do seu módulo bastante suscetível implementações confusas. Quando na verdade que você precisa é as instancias de sua classe “Veiculo”sejam tipos reais de carros, como BMW Boxster, ou Nisan 350Z. Observe a seguinte classe abstrata:


abstract class vehicle {
private double price;
private String model;
private String year;
private String manufacturer;
public abstract void goFast ();
public abstract void goUpHill ();
public abstract void impressNeighbors ();
// codificar o resto do código importante aqui

}


3)Regras de Declaração para Arquivos-Fontes

Já que estamos tratando de declarações e controles de acesso de classes, julgo então que este é um momento propício para fazermos uma breve revisão das regras pertinentes a declaração de classes, declarações import e declarações de package em um arquivo fonte:


1° - Só pode haver uma classe com escopo de visibilisdade “public” em cada arquivo de código-fonte.

2° - Os comentários podem aparecer no início ou no fim de qualquer linha no arquivo do código-fonte. Eles são independentes de qualquer das regras de posicionamento.

3° - Se houver uma classe pública em um arquivo, o nome do arquivo deve ser o mesmo desta classe . Por exemplo, uma classe declarada como “public class ZnVinho { }” precisa estar em um arquivo de código-fonte chamado “ZnVinho. java.”

4° - Se a classe fizer parte de um pacote, a declaração package deve estar na primeira linha do arquivo do código-fonte, antes de quaisquer declarações import que estejam presentes.

5° - Se houver declarações “import”, elas devem ficar entre a declaração package (se houver) e a declaração da classe. Se não houver uma declaração package, então a(s) declaração(ões) “import” deve(m) estar na(s) primeira(s) linha(s) do arquivo fonte. Se não houver declarações package nem import, então a declaração da classe deve estar na primeira linha do arquivo do fonte.

6° - As declarações import e package aplicam-se a todas as classes dentro de um arquivo fonte. Ou seja, não é possível declarar múltiplas classes em um arquivo e tê-la sem diferentes pacotes, ou usar diferentes importações.

7° - Um arquivo pode ter mais de uma classe não-pública.

8° - Arquivos que não tenham classes públicas podem ter um nome que não seja o mesmo de nenhuma das classesdo arquivo.


Posteriormente, aprofundaremos mais sobre as regras envolvidas com a declaração e o uso de importações, pacotes. Além disso, pretendo falar embreve sobre importações estáticas.

Referência:
SCJP: Certificação Sun para Programador Java 5 - Guia de Estudo

Artigo completo (View Full Post)

terça-feira, 23 de setembro de 2008

Servlet - HttpServlet Class - doGet & doPost

Sobrescrevendo os métodos herdados de “HttpServlet”

Baseado no que demonstramos no artigo anterior, “Java para Web no Netbeans 6 – Servlet, JSP & CSS”, quando me referi a superclasse “HttpServlet” sobre os métodos “doXXX”, neste artigo vou sobrescrever (override) os métodos “doGet” e “doPost” do Servlet que criamos anteriormente para testarmos a resposta de cada um deles mediante ao tipo de requisição cliente, quanto aos métodos http POST e GET. Lembre-se, estou contando com a mesma aplicação desenvolvida no artigo anterior. Neste artigo vou apenas sobrescrever os métodos citados a cima da classe “ZnLandjha”.





Código do método “doPost” de “ZnLandjha” sobrescrito:

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String znBla = request.getParameter("znBla");
if (znBla.equals("TestePost")){
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ZnLandjha - Método doPost Repondendo requisição Post </title>");
out.println("<link href=ZnCss/ZnCSSlandjah.css rel=stylesheet type=text/css>");
out.println("</head>");
out.println("<body>");
out.println("<div>Servlet ZnLandjha at Método doPost Repondendo requisição Post " +
"<br> Para tesar o método doGet Clik no botão ZN Abaixo." +
"</div> <br>");
out.println("<form name='formZnGet' method='GET'>");
out.println("<input type='submit' value='Ok Zn Get!' name='btnEnviarGet' /> <br>");
out.println("<input type='text' name='znBla' value=" + znBla + " size='32' />");
out.println(" </form>");
out.println("</body>");
out.println("</html>");

} finally {
out.close();
}
}
else{
processRequest(request, response);
}
}


Na linha 5: Recebendo do “Form” postado (do lado cliente) o valor do objeto “input” cujo nome é "znBla".

Na linha 6: O "if" testa se vamos processar o que foi programado no artigo anterior, ou se o processamento desejado é verificar a ação do método “doPost”. Ou seja, se no browser for digitado “TestePost”, você estará testando o método “doPost”.

Na Linha 19: Define a tag “Form” , da pagina que será montada em resposta ao processamento do método “doPost”, como: Name = “formZnGet” e method = “GET'”.

Na Linha 20: Definimos o botão que irá submeter a página que testa o método “doGet”. Para processar o teste, basta digitar “TesteGet” na caixa de texto.

Código do método “doGet” de “ZnLandjha” sobrescrito:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String znBla = request.getParameter("znBla");
if (znBla.equals("TesteGet")){
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ZnLandjha - Método doGet Repondendo requisição GET </title>");
out.println("<link href=ZnCss/ZnCSSlandjah.css rel=stylesheet type=text/css>");
out.println("</head>");
out.println("<body>");
out.println("<div>Servlet ZnLandjha at Método doGet Repondendo requisição GET " +
"<br> Para tesar o método doPost Clik no botão ZN Abaixo." +
"</div> <br>");
out.println("<form name=formZnPost method=POST>");
out.println("<input type='submit' value='Ok Zn Post!' name='btnEnviarPost' /> <br>");
out.println("<input type='text' name='znBla' value=" + znBla + " size='32' />");
out.println(" </form>");
out.println("</body>");
out.println("</html>");

} finally {
out.close();
}
}
else{
processRequest(request, response);}
}


Na linha 4: Recebendo do “Form” postado (do lado cliente) o valor do objeto “input” cujo nome é "znBla".

Na linha 5: O "if" testa se vamos processar o que foi programado no artigo anterior, ou se o processamento desejado é verificar a ação do método “doXXX”. Ou seja, se no browser for digitado “TesteGet”, você estará testando o método “doGet”. Só que para isso funcionar precisamos primeiro testar o “doPost”. Isso porque a primeira requisição vira da página “Index.jsp” e nela definimos que o método http, do “form1” é “POST”.

Execute (F6) e teste ...





OBS: "@Override" indica pro compilador que o método esta sobrescrito ...

Artigo completo (View Full Post)

segunda-feira, 22 de setembro de 2008

Java para Web no Netbeans 6 – Servlet, JSP & CSS

Java é uma linguagem de programação. Entretanto, quando nos referimos a Java como uma tecnologia estamos tratando de um grande conjunto composto por elementos distintos. Esses elementos de forma generalizada são: Padrões, frameworks e tecnologias. Esses três elementos combinados definem um outro elemento que são as arquiteturas.

Objetivo

Vamos construir um exemplo de aplicação Web onde experimentaremos de perto a complexidade de construir conteúdo dinâmico para Web. Conseqüentemente esbarraremos em algumas questões arquiteturais envolvendo tecnologia do lado cliente, e servidor. Veremos uma das soluções Java para este cenário.
Temos o arquivo Index.jsp, ele define a participação da tecnologia JSP na nossa arquitetura. Neste arquivo definiremos um formulário (objeto http form) que enviará dados para uma classe servlet a qual processará esses dados.

A tecnologia Java tem uma abordagem própria para desenvolvimento Web. Basicamente, quando você ouve falar em Java para Web invariavelmente escutará associado a esta idéia duas tecnologias: Servlet e JSP. Digo basicamente, porque as duas não são absolutas neste contexto. Existem outras, as quais vermos mais adiante, que cujo a utilização, quando feita adequadamente, pode oferecer para o desenvolver um ganho satisfatório.
A tecnologia Servlet desempenha um papel muito importante neste cenário, vamos neste artigo desenvolver um pequeno exemplo de uma aplicação Web em Java usando explicitamente a tecnologia Servlet. Meu principal objetivo e experimentar o Netbeans 6 para esse fim, durante esse processo pretendo tocar em pontos de importância básica pertinentes ou tema que escolhi inicialmente. Portanto, prossigamos:

Inicie um novo projeto Web no Netbeans 6 (Veja em “Um novo Projeto no Netbeans 6.”).




Entendendo um projeto Web Java

Veja na janela “Projects” (Project explorer vou chamar assim ...) , os diversos elementos que compõem o nosso projeto. Eles ficam organizados e dispostos numa estrutura hierarquizada de diretórios que são representados por uma Tree View a qual fornece acesso aos arquivos contidos por cada diretório.



O Diretório “Web Pages” é o principal, a raiz, de uma aplicação Java Web convencional. Contidos nele temos um arquivo index.jsp (que define a home page do site, por exemplo), além do diretório “WEB-INF” o qual contém o arquivo descritor de deploy (deployment descriptor), web.xml.

Configuration Files”, é o diretório onde ficam todos os arquivos referentes a configurações da aplicação web.

Source Packages”, velho conhecido, onde devem ficar todos os pacotes, classes Java e Servlets (obviamente, que serão criados durante o desenvolvimento da aplicação web).

Test Package”, para testes unitários.

As bibliotecas ficam em “Libraries”, exceto as que forem necessárias aos testes que devem ficar em “Tests Libraries” (por default as bibliotecas do Junit 3.8.2 e 4.1 já serão adicionadas nesta pasta).



Usando CSS

Vou criar um arquivo CSS o qual usarei neste exemplo. Para armazená-lo, vou criar um novo diretório dentro de “Web Pages”, a este chamarei de “ZnCss”. Com o botão direito do mouse, na treeview do project explorer, sobre a pasta “Web Pages” selecione New ► Folder, conforme ilustração abaixo:




O Netbeans, através do assistente vai auxiliar este trabalho. Em “Folder Name” digite o nome desejado para o novo diretório. Note que, você pode também definir a hierarquia desse novo diretório em “Parent Folder”. Para completar a criação do diretório click em “Finish”.



Para criar o arquivo CSS, selecione, com o botão direito do mouse no novo diretório, a opção New ►Other, para acessar o assistente. Em seguida, dentre as opções listadas, na categoria “Web”, selecione “Cascading Style Sheet”. Click em “Next” para continuar a criação do arquivo CSS.



Em “CSS File Name” digite o nome do arquivo: “ZnCSSlandjah”. Veja que “Location” e “Folder” já estão definidos em decorrência de termos selecionado o diretório “ZnCss”.



Click em “Finish” e seu arquivo será criado. Esse foi meu primeiro contato com o editor de CSS do Netbeans 6, gostei! Basta você digitar a classe, ou tag que deseja redefinir, e intuitivamente é possível usar os recursos da IDE para edição de CSS.
O Preview lhe permite em tempo de design ver o efeito do css que você está editando.

A seguir o código do meu css

/*
Document : ZnCSSlandjah
Created on : 22/09/2008, 10:59:57
Author : Gmotta Zn
Description:
Purpose of the stylesheet follows.
*/

div{
font-family: Cosmic Sans, Veranda,Tahoma;
font-size: 14px;
background-color: #330099;
color: #ccff99;
font-weight: bolder;
text-align: center;

}


Editando o arquivo Index.jsp

Quando iniciamos um projeto Web no Netbeans ele define no deployment descriptor qual o arquivo será executado quando o Glass Fish atender uma requisição cliente chamando a URL do seu serviço. Esse arquivo, por default é o Index.jsp. Você pode alterar isso no o arquivo “web.xml” (basta um duplo click sobre o arquivo, ou com o botão direito selecione “Open”), pela IDE na aba “Pages”.



Na tag “head” do arquivo “Index.jsp” vou linkar o CSS “ZnCSSlandjah.css”.


<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF- 8">
<title>Estação ZN - Nova JSP Page</title>
<link href="ZnCss/ZnCSSlandjah.css" rel="stylesheet" type="text/css">


O próximo passo será adicionar um “form” para postar dados para efetuarmos um processamento qualquer no servidor. Na janela “Palhette” (provavelmente ela deve estar no lado direito da IDE), selecione em “HML Forms” um objeto “Form”, click sobre ele e arraste para um local, entre a abertura e o fechamento da tag “body”. Em seguida prossiga com o assistente.



Em “Action” vou digitar “ZnLandjha” (esse vai ser o nome do Servlet que criarei posteriormente), o “method” selecione "POST".



O Editor no Netbeans é sensacional, veja um code insigth para HTML muito bom.



Agora, o “body” da minha página jsp está assim: (indexJSP.txt)

<body>
<h2> Estação ZN - Servlets </h2>
<h3> GlassFish <h3>
<div>
www.estacaozn.blogspot.com
</div>
<br>

<form name="form1" action="ZnLandjha" method="POST">

</form>
</body>


OBS: Na tag "div" pretendo aplicar o efeito do CSS ...

Vou adicionar um objeto HTML “Table” na minha página aonde pretendo colocar os “inputs”. Depois de editar o código, digite conforme ilustrado abaixo:


<%--
Document : index
Created on : 18/09/2008, 03:25:39
Author : GMotta Zn
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Estação ZN - Nova JSP Page</title>
<link href="ZnCss/ZnCSSlandjah.css" rel="stylesheet"
type="text/css">

</head>
<body>
<h2> Estação ZN - Servlets </h2>
<h3> GlassFish <h3>
<div>
www.estacaozn.blogspot.com
</div>
<br>

<form name="form1" action="ZnLandjha" method="POST">
<div>
<table border="0" cellpadding="1">
<tbody>
<tr>
<td>
Digite o Nome:
</td>
<td>
<input type="text" name="znBla" value="Bla!"
size="32" />
</td>
</tr>
<tr>
<td>
<input type="submit" value="Ok Zn" name="btnEnviar"
/>
</td>
<td>
Netbeans 6 - Servlet, JSP & CSS
</td>
</tr>
</tbody>
</table>
</div>
</form>
</body>
</html>



Criando o Servlet

Com o botão direito do mouse no que eu chamo de “Project Explore”, selecione a opção: New ►Servlet




O Nome da Classe servlet vai ser “ZnLandjha”. Note que o assistente já define pra você o projeto (Project: AppWebServletsZN, não editável) e o diretório (Location: Source Pakcages) onde será criado o arquivo onde está defina a classe que vamos codificar. Ainda não definimos uma package para nosso projeto, isso deverá ser feito neste momento. Digite “ZnWebLandjahPkg” em Pakcage. Veja ilustração abaixo:



Clicando em “Next” você pode configurar a URL de chamada ao seu servlet mediante ao valor digitado em “URL Pattern(s):”. Todas as informações definidas precisam ser persistidas no “Deployment Descriptor”, o arquivo “web.xml”. Portanto, a opção “Add information to deployment descriptor” deve ficar selecionada. Logo, vou deixar tudo como está neste diálogo e finalizar aqui. Click em “Finish”.



Codificando o Servlet “ZnLandjha”

package ZnWebLandjahPkg;

import java.io.*;
import java.net.*;
import java.util.Iterator;
import javax.servlet.*;
import javax.servlet.http.*;

/**
* @author GMottaZn
*/
public class ZnLandjha extends HttpServlet {

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String znBla = request.getParameter("znBla");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet ZnLandjha</title>");
out.println("<link href=ZnCss/ZnCSSlandjah.css rel=stylesheet type=text/css>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet ZnLandjha at " + request.getContextPath
() + "</h1> <br>");
out.println("<h4> Você Digitou: " + znBla + "</h4> <br>");
out.println("<div> Ivertendo temos: " + inverterZn(znBla)+ "</div>");
out.println("</body>");
out.println("</html>");

} finally {
out.close();
}
}

protected String inverterZn(String znValue){
StringBuffer znAux = new StringBuffer(znValue);
znAux.reverse();
return znAux.toString();
};

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Handles the HTTP <code>POST</code> method.
* @param request servlet request
* @param response servlet response
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Returns a short description of the servlet.
*/
public String getServletInfo() {
return "Short description";
}
// </editor-fold>
}


Até que em fim um pouco de código Java. Analisado o código acima:

Linha 1: referência ao pacote (package).

Linha 3 – 7: importação de bibliotecas.

Linha 9-11: Comentário para documentação.

Linha 12- 71: Codificação da classe “ZnLandjha”, que estende de “HttpServlet” (Superclasse para Servlet). A classe “HttpServlet” estende a classe javax.servlet.GenericServlet. Ela acrescenta os métodos “doXXXX” que são executados mediante as requisições “http”. “doGet”, “doPost”, “doPut”, “doDelete”, “doOption” e “doTrave”. Cada um desses métodos são chamados em resposta a um método http evocado. Exemplo: O método “doGet” é executado quando o Servlet recebe uma requisição (de uma página que submeteu um “form”) que foi enviada ao servidor web (por exemplo, o Glass Fish) usando o método http “GET”.




Linha 16: Recebendo do “Form” postado (do lado cliente) o valor do objeto “input” cujo nome é "znBla" (O qual foi definido no arquivo “Index.jsp”).

Linha 19-34: Dentro de um bloco protegido (try...), monta a página para saída dos valores processados pelo Servlet “ZnLandjha”.

Linha 28: Saída do valor processado pelo método protegido que codificamos “inverterZn”.

Linha 37-41: Método protected “inverterZn”, responsável pela inversão da string digitada pelo cliente. A inversão está sendo efetuada na linha 39, pela execução do método “reverse”. Na linha 40 uso o método “toString” para poder atribuir o valor de “znAux”, que é do tipo “StringBuffer”, para String e dessa forma posso retornar o valor invertido no método em questão.

Agora vamos fazer o deploy da nossa aplicação, com o botão direito sobre a raiz do projeto no “project explorer”, selecione “Undeploy and Deploy”.




Testando aplicação criada

Para testar basta pressionar F6, ou na barra de ferramentas click sobre o triângulo verde.



O browser vai ser executado ...



Digite alguma coisa na caixa de texto e submeta ...



O Servlet processou a requisição ...




Fontes deste artigo

Artigo completo (View Full Post)

Um novo Projeto no Netbeans 6

Um novo Projeto no Netbeans 6

Existem algumas opções para iniciarmos um novo projeto no Netbeans .... Vejamos:

Opções:

1)      No Menu File ►new Project (Ctrl+Shift+N)





2) Com o botão direto do mouse sobre a janela “Projects”(Tipo um Project Explorer, no lado direito da IDE)



No diálogo seguinte, no primeiro passo, devemos escolher que tipo de projeto vamos iniciar. Observe em “Categories” vários tipos diferentes para projetos Java no Netbeans.




No segundo passo, definiremos o nome do projeto o diretório onde ficarão os arquivos fontes criados para o projeto em questão.



Propriedades do seu projeto

Em “Project Name”, digite um nome adequado que você vai criar para seu projeto: Exemplo: “MeuExemploZnServlets”.



Em, “Project Location” o botão “browse” disponibiliza um janela, tipo API do Windows, para você definir um diretório onde ficarão os arquivos do seu projeto.

Outros detalhes específicos do tipo do projeto também devem ser definidos ainda neste diálogo. Por exemplo, no caso de um projeto Web você pode definir o servidor web (GlassFish, por exemplo) em Server, a versão Java EE. O “Context Path” é o nome de contexto de acesso ao seu projeto.

Click em Finish para concluir a criação do seu novo projeto. Em alguns casos poderiam existir outras definições sobre o projeto. Como por exemplo, em aplicações web haveria um terceiro passo, no botão “Next”, para seleção opcional de um Framework.




A opção “Set as Main Project” indica para IDE qual o prjeto será compliado toda vez que os comandos de “Build” (F11 – Build Main Project) e “Run” (F6 – Run Main Project) forem, por você na IDE, executados.







Artigo completo (View Full Post)

domingo, 10 de agosto de 2008

Modularização em Programação: Coesão X Acoplamento, OO X Estruturação, Portugol X UML - a partir de um algoritmo simples

Algoritmo III – Um passo além ... continuação

Esse artigo é continuação de Algoritmo III – Um passo além da teoria. Onde ficou faltando exemplificarmos a estrutura de desvio condicional aninhado. Pretendo agora completar o que ficou pendente e, na mesma linha de abordagem que venho adotando ao falar sobre algoritmos, aproveitar também para destacar alguns pontos importantes que implicam na aplicação pratica do conhecimento sobre algoritmos. Portanto, além de mostrar exemplos da implementação do algoritmo em diferentes linguagens, criarei versões diferentes do mesmo exemplo onde demonstrarei o efeito da modularização, suas vantagens, bem como apontar uma caminho de como fazer isso. Que lógica seguir, qual o alvo buscar na hora de pensar em modularizar um programa.
Agora que está claro o que iremos fazer, falta explicar o “como”. Usarei um único algoritmo. Um que seja muito simples. Ao ponto de a única coisa nele que vale apena ser mencionada é o fato que ele implementa a estrutura de desvio condicional aninhado. Desta forma estamos focados no que tange ao conceito lógico que desejamos abordar. Por isso o algoritmo escolhido será o tradicional e simplório algoritmo de verificação do maior e o menor valor entre três números. Delphi e Java, a princípio, são as linguagens que usarei. Quanto a modularização, iniciaremos com o um primeiro exemplo bem primário onde codificarei o programa de forma seqüencial, todo num único fluxo. Forma mais comumente adotada (infelizmente). Em seguida, numa segunda versão evoluiremos o primerio exemplo aplicando um nível de modularização sob uma perspectiva estruturada. Para finalizar, construiremos uma terceira versão aumentando o grau de modularização sob uma perspectiva OO. O fato de neste terceiro exemplo o grau de modularização ser maior que o anterior não está diretamente relacionado com a abordagem OO. Ou seja, também é possível alcançar o mesmo grau usando estruturação.
Partiremos agora para a construção do primeiro exemplo do algoritmo que determina o Maior e o Menor valor entre três valores digitados.

Algoritmo não modularizado – aplicando a estrutura de decisão “desvio condicional”: Esse é o nosso ponto de partida ...


PROGRAMA DeterminaMaiorMenor;
VARIÁVEIS
Num1Zn, Num2Zn, Num3Zn: NUMÉRICO;
INÍCIO
LEIA (Num1Zn, Num2Zn, Num3Zn);

// Determinando o maior valor
SE (Num1Zn > Num2Zn) E (Num1Zn > Num3Zn) ENTÃO
ESCREVER (“Maior = ” + Num1Zn)
SENÃO SE (Num2Zn > Num1Zn) E (Num2Zn > Num3Zn) ENTÃO
ESCREVER (“Maior = ” + Num2Zn)
SENÃO
ESCREVER (“Maior = ” + Num3Zn);

// Determinando o menor valor
SE (Num1Zn < Num2Zn) E (Num1Zn < Num3Zn) ENTÃO
ESCREVER (“Menor = ” + Num1Zn)
SENÃO SE (Num2Zn < Num1Zn) E (Num2Zn < Num3Zn) ENTÃO
ESCREVER (“Menor = ” + Num2Zn)
SENÃO
ESCREVER (“Menor = ” + Num3Zn)

FIM.



O algoritmo não deve apresentar detalhes específicos da tecnologia definida pela linguagem. Por isso você vai perceber que na implementação do algoritmo numa linguagem vai aparecer linhas de código a mais, que objetivam lidar com detalhes exclusivos da tecnologia. Entretanto, o algoritmo pode e deve apresentar uma modularização adequada. Veremos adiante.

Implementando o algoritmo não modularizado em Delphi


procedure TForm1.Button1Click(Sender: TObject);
var
Num1Zn, Num2Zn, Num3Zn, ZnMaior, ZnMenor: Double;
StrNum1Zn, StrNum2Zn, StrNum3Zn, MsgSaida: String;
SaoIguais: boolean ;
begin
// Entrada de dados
StrNum1Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor', 'Digite o número', '');
StrNum2Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor', 'Digite o número', '');
StrNum3Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor', 'Digite o número', '');

// Processamento
Num1Zn := StrToFloat(StrNum1Zn);// convertendo de string para Double
Num2Zn := StrToFloat(StrNum2Zn);// convertendo de string para Double
Num3Zn := StrToFloat(StrNum3Zn);// convertendo de string para Double

// Comparando para encontrar o maior
(***********************************)
(* Antes, testo se eles são iguais *)
SaoIguais := (Num1Zn = Num2Zn) and (Num1Zn = Num3Zn);
if SaoIguais then
begin
msgSaida := 'Os números são iguais - %f';
ZnMaior := Num1Zn;
end
else
begin
// Determinando o maior valor
msgSaida := 'O maior número é: %f';
if ((Num1Zn > Num2Zn) and (Num1Zn > Num3Zn)) then
ZnMaior := Num1Zn
else if ((Num2Zn > Num1Zn) and (Num2Zn > Num3Zn)) then
ZnMaior := Num2Zn
else
ZnMaior := Num3Zn;

// Determinando o menor valor
msgSaida := msgSaida + ' | O menoor número é: %f';
if ((Num1Zn < Num2Zn) and (Num1Zn < Num3Zn)) then
ZnMenor := Num1Zn
else if ((Num2Zn < Num1Zn) and (Num2Zn < Num3Zn)) then
ZnMenor := Num2Zn
else
ZnMenor := Num3Zn;
end;

(*Saída de dados*)
Self.Canvas.Refresh;
Self.Canvas.TextOut(12, 70, 'www.estacaozn.blogspot.com');
Self.Canvas.TextOut(12, 100, Format(MsgSaida, [ZnMaior, ZnMenor]));
end;



Observe que temos código demais para uma tarefa tão simples ...

Implementando o algoritmo não modularizado em Java

package verificamaiorzn;

import javax.swing.JOptionPane;

/**
*
* @author GMottaZn
*/
public class Main {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String strNum1Zn, strNum2Zn, strNum3Zn,msgSaida;
double Num1Zn, Num2Zn, Num3Zn, ZnMaior, ZnMenor;
boolean saoIguais;
// Entrada de dados
strNum1Zn = JOptionPane.showInputDialog("Digite o primeiro zn número");
strNum2Zn = JOptionPane.showInputDialog("Digite o segundo zn número");
strNum3Zn = JOptionPane.showInputDialog("Digite o terceiro zn número");

// processamento
Num1Zn = Double.parseDouble(strNum1Zn); // convertendo de string para Double
Num2Zn = Double.parseDouble(strNum2Zn); // convertendo de string para Double
Num3Zn = Double.parseDouble(strNum3Zn); // convertendo de string para Double
// Comparando para encontrar o maior
// Antes, testo se eles são iguais
saoIguais = (Num1Zn == Num2Zn) && (Num1Zn == Num3Zn);
if (saoIguais){
msgSaida = "Os números são iguais - ";
ZnMaior = Num1Zn;
}// então procuro o maior
else {
msgSaida = "O maior número é: ";
if ((Num1Zn > Num2Zn) &&(Num1Zn > Num3Zn)){
ZnMaior = Num1Zn;
}
else {
if ((Num2Zn > Num1Zn) &&(Num2Zn > Num3Zn)){
ZnMaior = Num2Zn;
}
else
ZnMaior = Num3Zn;
};
//Determina o menor valor
msgSaida = msgSaida + " | O menor número é: ";
if ((Num1Zn < Num2Zn) &&(Num1Zn < Num3Zn)){
ZnMenor = Num1Zn;
}
else {
if ((Num2Zn < Num1Zn) &&(Num2Zn < Num3Zn)){
ZnMenor = Num2Zn;
}
else
ZnMenor = Num3Zn;
};
};
// Saída de dados
JOptionPane.showMessageDialog(null, " Estação Zn - " + msgSaida + ZnMaior,
"www.estacaozn.blogspot.com", JOptionPane.INFORMATION_MESSAGE);

// Finaliza programa
System.exit(0);

}
}



Modificando o Algoritmo para que ele apresente o primeiro nível de modularização. Vamos transformar o fluxo que determina o maior valor e transformar numa sub-rotina (um sub-programa). Faremos o mesmo para o segundo fluxo, o que determina o menor valor. Logo, teremos nosso algoritmo modularizado em duas sub-rotinas independentes, cada uma com um objetivo específico.


PROGRAMA DeterminaMaiorMenor;
VARIÁVEIS
Num1Zn, Num2Zn, Num3Zn: NUMÉRICO;
// primeira sub-rotina
Função EncontraMaior(Num1Zn, Num2Zn, Num3Zn: Double): String;
Constatnte
MsgSaida = 'O maior número é: ;
var
ZnMaior: Double;
Início
// Determinando o maior valor
SE (Num1Zn > Num2Zn) E (Num1Zn > Num3Zn) ENTÃO
ZnMaior := Num1Zn
SENÃO SE (Num2Zn > Num1Zn) E (Num2Zn > Num3Zn) ENTÃO
ZnMaior := Num2Zn)
SENÃO
ZnMaior := Num3Zn);

EncontraMaior := MsgSaida + ZnMaior;
Fim;

// segunda sub-rotina
Função EncontraMenor(Num1Zn, Num2Zn, Num3Zn: Double): String;
Constatnte
MsgSaida = 'O maior número é: ;
var
ZnMenor: Double;
Início
// Determinando o menor valor
SE (Num1Zn < Num2Zn) E (Num1Zn < Num3Zn) ENTÃO
ZnMenor := Num1Zn
SENÃO SE (Num2Zn < Num1Zn) E (Num2Zn < Num3Zn) ENTÃO
ZnMenor := Num2Zn)
SENÃO
ZnMenor := Num3Zn);

EncontraMenor := MsgSaida + ZnMenor;
Fim;

função SaoIguais(Num1Zn, Num2Zn, Num3Zn: Double): Boolean;
Início
SaoIguais := (Num1Zn = Num2Zn) and (Num1Zn = Num3Zn);
Fim;
//Programa principal
INÍCIO
LEIA (Num1Zn, Num2Zn, Num3Zn);
SE SaoIguais(Num1Zn, Num2Zn, Num3Zn) ENTÃO
ESCREVA(“Os números são iguais”)
SENÃO
INÍCIO
ESCREVA(“O menor número é: ” + EncontraMenor(Num1Zn, Num2Zn, Num3Zn));
ESCREVA(“O maior número é: ” + EncontraMaior(Num1Zn, Num2Zn, Num3Zn));
FIM;

FIM.


Sub-Rotina – Comumente chamamos as sub-rotinas de “Procedimentos” (procedure) ou “Funções” (function). Podemos entendê-las como um trecho de programa escrito separadamente.


Implementando o algoritmo modularizado em Delphi
Primeiro as sub-rotinas


function EncontraMaior(const Num1Zn, Num2Zn, Num3Zn: Double): String;
const
MsgSaida = 'O maior número é: %f';
var
ZnMaior: Double;
begin
// Determinando o maior valor
if ((Num1Zn > Num2Zn) and (Num1Zn > Num3Zn)) then
ZnMaior := Num1Zn
else if ((Num2Zn > Num1Zn) and (Num2Zn > Num3Zn)) then
ZnMaior := Num2Zn
else
ZnMaior := Num3Zn;
Result := Format(MsgSaida, [ZnMaior]);
end;



function EncontraMenor(const Num1Zn, Num2Zn, Num3Zn: Double): String;
const
MsgSaida = 'O menor número é: %f';
var
ZnMaior: Double;
begin
// Determinando o menor valor
if ((Num1Zn < Num2Zn) and (Num1Zn < Num3Zn)) then
ZnMaior := Num1Zn
else if ((Num2Zn < Num1Zn) and (Num2Zn < Num3Zn)) then
ZnMaior := Num2Zn
else
ZnMaior := Num3Zn;
Result := Format(MsgSaida, [ZnMaior]);
end;

Verificar se os valores são iguais é um plus ... então vai ...

function SaoIguais(const Num1Zn, Num2Zn, Num3Zn: Double; var MsgSaida: String): Boolean;
const
AMsgSaida = 'Os números são iguais: %f';
begin
Result := (Num1Zn = Num2Zn) and (Num1Zn = Num3Zn);
if Result then
MsgSaida := Format(AMsgSaida, [Num1Zn]);
end;

A seguir codificaremos o programa principal "DeterminaMaiorMenor"


procedure TForm1.Button2Click(Sender: TObject);
var
Num1Zn, Num2Zn, Num3Zn: Double;
StrNum1Zn, StrNum2Zn, StrNum3Zn, MsgSaida: String;
begin
// Entrada de dados
StrNum1Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');
StrNum2Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');
StrNum3Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');

// Processamento
Num1Zn := StrToFloat(StrNum1Zn);// convertendo de string para Double
Num2Zn := StrToFloat(StrNum2Zn);// convertendo de string para Double
Num3Zn := StrToFloat(StrNum3Zn);// convertendo de string para Double
if not (SaoIguais(Num1Zn, Num2Zn, Num3Zn, MsgSaida)) then
begin
MsgSaida := EncontraMaior(Num1Zn, Num2Zn, Num3Zn);
MsgSaida := MsgSaida + ' | ' + EncontraMenor(Num1Zn, Num2Zn, Num3Zn);
end;

(*Saída de dados*)
Self.Canvas.Refresh;
Self.Canvas.TextOut(12, 70, 'www.estacaozn.blogspot.com');
Self.Canvas.TextOut(12, 100, MsgSaida);
end;


Observe que o número de linhas do programa principal diminuiu sensivelmente. Entretanto, o que é pouco comentado a respeito de modularização é que a quantidade de variáveis também tende a reduzir. Isso é um ganho muito importante na qualidade do seu código. Note que reduzimos de dez variáveis no primeiro exemplo para sete no segundo.


Implementando o algoritmo modularizado em Java

package verificamaiormenor;

import javax.swing.JOptionPane; // Importando pacote de extenção Java API
/**
*
* @author GMottaZn
*/
public class Main {
// Atributos privados
private double num3Zn;
private double num2Zn;
private double num1Zn;
private String znMsgSaida;

public double getNum3Zn() {
return num3Zn;
}

public void setNum3Zn(double num3Zn) {
this.num3Zn = num3Zn;
}

public double getNum2Zn() {
return num2Zn;
}

public void setNum2Zn(double num2Zn) {
this.num2Zn = num2Zn;
}

public double getNum1Zn() {
return num1Zn;
}

public void setNum1Zn(double num1Zn) {
this.num1Zn = num1Zn;
}

public String getZnMsgSaida() {
return znMsgSaida;
}

public void setZnMsgSaida(String znMsgSaida) {
this.znMsgSaida = znMsgSaida;
}

// Metodos privados
private String encontraMaior() {
double znMaior;
if ((getNum1Zn() > getNum2Zn()) && (getNum1Zn() > getNum3Zn())) {
znMaior = getNum1Zn();
}
else {
if ((getNum2Zn() > getNum1Zn()) && (getNum2Zn() > getNum3Zn())) {
znMaior = getNum2Zn();

}
else {
znMaior = getNum3Zn();
}
}
return "O Maior Número é: " + znMaior;
}

private String encontraMenor() {
double znMenor;
if ((getNum1Zn() < getNum2Zn()) && (getNum1Zn() < getNum3Zn())) {
znMenor = getNum1Zn();
}
else {
if ((getNum2Zn() < getNum1Zn()) && (getNum2Zn()< getNum3Zn())) {
znMenor = getNum2Zn();

}
else {
znMenor = getNum3Zn();
}
}
return "O Menor Número é: " + znMenor;
}

private boolean saoIguais(){
return (getNum1Zn() == getNum2Zn()) && (getNum1Zn() == getNum3Zn());
}

// Método Público
public void executaVerificacao(){
String saidaMaior, saidaMenor;
if (saoIguais()){
saidaMaior = "Os números são iguais: " + getNum1Zn();
setZnMsgSaida(saidaMaior);
}
else{
saidaMaior = encontraMaior();
saidaMenor = encontraMenor();
setZnMsgSaida(saidaMaior + " | " + saidaMenor);
}

}

public static void main(String[] args) {
String strNum1Zn, strNum2Zn, strNum3Zn, msgSaida;

// Entrada de dados ...
strNum1Zn = JOptionPane.showInputDialog("Digite o primeiro zn número");
strNum2Zn = JOptionPane.showInputDialog("Digite o segundo zn número");
strNum3Zn = JOptionPane.showInputDialog("Digite o terceiro zn número");
/**
* Instanciando um objeto cujo o tipo é a classe "Main".
* O construtor "Main()" retorna um referencia de memória para a variável "MyZnClass"
*/
Main MyZnClass = new Main();

// Atribuindo valor aos atributos
MyZnClass.setNum1Zn(Double.parseDouble(strNum1Zn));
MyZnClass.setNum2Zn(Double.parseDouble(strNum2Zn));
MyZnClass.setNum3Zn(Double.parseDouble(strNum3Zn));
//PROCESSA a verificação para encontrar o maior e o menor valor
MyZnClass.executaVerificacao();

// Saída de dados
JOptionPane.showMessageDialog(null, " Estação Zn - " +
MyZnClass.getZnMsgSaida(), "www.estacaozn.blogspot.com",
JOptionPane.INFORMATION_MESSAGE);

// Finaliza programa
System.exit(0);


}
}

Este tipo modularização, em linguagens como o Java apresnta pouca melhoria em termos visuais como, por exemplo, comparado ao Delphi. Isso se olharmos o todo do programa. Entretanto, se considerarmos apenas o programa principal, que se inicia na linha 101 (public static void main(String[] args)) é nítido o ganho na qualidade do código.

Chegamos a um nível de complexidade mais avançado do tema proposto. Caminhamos progressivamente no sentido de fornecer conteúdo pratico e teórico(veja sub-rotinas e O princípio da caixa preta) para fortalecer o ponto de vista que estou tentando apresentar. Vamos aumentar o grau de modularização do nosso simplório algoritmo usando a orientação a objetos.


Implementando o algoritmo modularizado em Delphi
primeiro codificaremos a classe que encontrará o maior e o menor valor...


unit DeterminaMaiorMenorZN;

interface

uses
classes, SysUtils;

(*********************************************************************
* Nesta unit definimos uma Classe que possui um comportamento capaz *
* de determinar qual o maior e o menor valor entre três valores *
* atribuidos a ela. (GMttaZn - 07/2008) *
********************************************************************)

type
TDeterminaMaiorMenorZN = Class(TComponent)
private
(* Atributos Privados *)
FNum3Zn: Double;
FNum1Zn: Double;
FNum2Zn: Double;
FZnMsgSaida: String;
(* métodos setters *)
procedure SetNum1Zn(const Value: Double);
procedure SetNum2Zn(const Value: Double);
procedure SetNum3Zn(const Value: Double);
procedure SetZnMsgSaida(const Value: String);

(* Metodos privados *)
function EncontraMaior: Double;
function EncontraMenor: Double;
function SaoIguais: boolean;
public
procedure ExecutaVerificacao;
(* Propriedades - são os getters e setters em Delphi *)
property Num3Zn: Double read FNum3Zn write Setnum3Zn;
property Num2Zn: Double read FNum2Zn write Setnum2Zn;
property Num1Zn: Double read FNum1Zn write Setnum1Zn;
property ZnMsgSaida: String read FZnMsgSaida write SetznMsgSaida;
end;
implementation

const
// Definindo constantes
MSG_MAIOR_ZN = 'Maior Número = %f';
MSG_MENOR_ZN = 'Menor Número = %f';
MSG_IGUAIS_ZN = 'São Iguais = %f';

{ TDeterminaMaiorMenorZN }

(**********************************************************
* Inmplementa um algoritmo para determinar o maior entre *
* três valores - http://estacaozn.blogspot.com *
**********************************************************)
function TDeterminaMaiorMenorZN.EncontraMaior: Double;
begin
if ((FNum1Zn > FNum2Zn) and (FNum1Zn > FNum3Zn)) then
Result := Num1Zn
else if ((FNum2Zn > FNum1Zn) and (FNum2Zn > FNum3Zn)) then
Result := FNum2Zn
else
Result := FNum3Zn;
end;

(**********************************************************
* Inmplementa um algoritmo para determinar o menor entre *
* três valores - http://estacaozn.blogspot.com *
**********************************************************)
function TDeterminaMaiorMenorZN.EncontraMenor: Double;
begin
if ((FNum1Zn < FNum2Zn) and (FNum1Zn < FNum3Zn)) then
Result := Num1Zn
else if ((FNum2Zn < FNum1Zn) and (FNum2Zn < FNum3Zn)) then
Result := FNum2Zn
else
Result := FNum3Zn;
end;

(*****************************************************************************
* Evoca os métodos que determinam o maior e o menor valor dos atributos *
* da classe. Testando, primeiramente se os valores não são iguais. Desta *
* forma então, definido um valor adequado para a saída. *
* - http://estacaozn.blogspot.com *
*****************************************************************************)
procedure TDeterminaMaiorMenorZN.ExecutaVerificacao;
var
SaidaMaior, SaidaMenor: String ;
begin
if (SaoIguais) then
SetZnMsgSaida(Format(MSG_IGUAIS_ZN, [Num1Zn]))
else
begin
SaidaMaior := Format(MSG_MAIOR_ZN, [EncontraMaior]);
SaidaMenor := Format(MSG_MENOR_ZN, [EncontraMenor]);
SetZnMsgSaida(SaidaMaior + ' | ' + SaidaMenor);
end;
end;

(* Determina se o valor dos atributos são guais - http://estacaozn.blogspot.com*)
function TDeterminaMaiorMenorZN.SaoIguais: boolean;
begin
Result := (Num1Zn = Num2Zn) and (Num1Zn = Num3Zn);
end;

procedure TDeterminaMaiorMenorZN.Setnum1Zn(const Value: double);
begin
FNum1Zn := Value;
end;

procedure TDeterminaMaiorMenorZN.Setnum2Zn(const Value: double);
begin
FNum2Zn := Value;
end;

procedure TDeterminaMaiorMenorZN.Setnum3Zn(const Value: double);
begin
FNum3Zn := Value;
end;

procedure TDeterminaMaiorMenorZN.SetznMsgSaida(const Value: String);
begin
FZnMsgSaida := Value;
end;

end.

Program principal - no contexto da nossa modularização


procedure TForm1.Button3Click(Sender: TObject);
var
MyDeterminaMaiorMenorZn: TDeterminaMaiorMenorZN;
StrNum1Zn, StrNum2Zn, StrNum3Zn, MsgSaida: String;
begin
// Entrada de dados
StrNum1Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');
StrNum2Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');
StrNum3Zn := InputBox('www.estacaozn.blogspot.com | Encontra o Maior Valor',
'Digite o número', '');

// Processamento
MyDeterminaMaiorMenorZn := TDeterminaMaiorMenorZN.Create(Self);
try
MyDeterminaMaiorMenorZn.Num1Zn := StrToFloat(StrNum1Zn);// convertendo de string para Double
MyDeterminaMaiorMenorZn.Num2Zn := StrToFloat(StrNum2Zn);// convertendo de string para Double
MyDeterminaMaiorMenorZn.Num3Zn := StrToFloat(StrNum3Zn);// convertendo de string para Double

MyDeterminaMaiorMenorZn.ExecutaVerificacao;

(*Saída de dados*)
Self.Repaint;
//Self.Canvas.Refresh;
Self.Canvas.TextOut(250, 90, 'www.estacaozn.blogspot.com');
Self.Canvas.TextOut(250, 110, MyDeterminaMaiormenorZn.ZnMsgSaida);
finally
MyDeterminaMaiorMenorZn.Free;
end;
end;

Note no exemplo acima que a quantidade de varaáveis foi reduzido ainda mais.

Implementando o algoritmo modularizado em Java
Primeiro a classe responsável por determinar o maior e o menor valor


package modularizandoverificamaiormenoroo;

/**
*
* @author GMottaZN
* www.estacaozn.blogspot.com
* Este exemplo foi construido com objetivo de demostrar
* as vantagens de mudularizar um programa. Aplicamos uma abordagem OO
* para alcançar este objetivo.
*/
public class DeterminaMaiorMenorZN {

// Atributos privados
private double num3Zn;
private double num2Zn;
private double num1Zn;
private String znMsgSaida;

// Definindo constantes
final static String MSG_MAIOR_ZN = "Maior Número = ";
final static String MSG_MENOR_ZN = "Menor Número = ";
final static String MSG_IGUAIS_ZN = "São Iguais = ";

// getters e setters
public double getNum3Zn() {
return num3Zn;
}

public void setNum3Zn(double num3Zn) {
this.num3Zn = num3Zn;
}

public double getNum2Zn() {
return num2Zn;
}

public void setNum2Zn(double num2Zn) {
this.num2Zn = num2Zn;
}

public double getNum1Zn() {
return num1Zn;
}

public void setNum1Zn(double num1Zn) {
this.num1Zn = num1Zn;
}

public String getZnMsgSaida() {
return znMsgSaida;
}

public void setZnMsgSaida(String znMsgSaida) {
this.znMsgSaida = znMsgSaida;

}

// Metodos privados
private double encontraMaior() {
/**
* Inmplementa um algoritmo para determinar o maior entre
* três valores - http://estacaozn.blogspot.com
*/
double znMaior;
if ((getNum1Zn() > getNum2Zn()) && (getNum1Zn() > getNum3Zn())) {
znMaior = getNum1Zn();
}
else {
if ((getNum2Zn() > getNum1Zn()) && (getNum2Zn() > getNum3Zn())) {
znMaior = getNum2Zn();

}
else {
znMaior = getNum3Zn();
}
}
return znMaior;
}

private double encontraMenor() {
/**
* Inmplementa um algoritmo para determinar o menor entre
* três valores - http://estacaozn.blogspot.com
*/
double znMenor;
if ((getNum1Zn() < getNum2Zn()) && (getNum1Zn() < getNum3Zn())) {
znMenor = getNum1Zn();
}
else {
if ((getNum2Zn() < getNum1Zn()) && (getNum2Zn()< getNum3Zn())) {
znMenor = getNum2Zn();

}
else {
znMenor = getNum3Zn();
}
}
return znMenor;
}

private boolean saoIguais(){
/**
* Verifica se os valores atribuidos aos atributos da classe
* são iguais - http://estacaozn.blogspot.com
*/
return (getNum1Zn() == getNum2Zn()) && (getNum1Zn() == getNum3Zn());
}

// Método Público
public void executaVerificacao(){
String saidaMaior, saidaMenor;

if (saoIguais()){
setZnMsgSaida(MSG_IGUAIS_ZN + getNum1Zn());
}
else{
saidaMaior = MSG_MAIOR_ZN + encontraMaior();
saidaMenor = MSG_MENOR_ZN + encontraMenor();
setZnMsgSaida(saidaMaior + " | " + saidaMenor);
}

}

}



Programa principal Java


package modularizandoverificamaiormenoroo;

import javax.swing.JOptionPane;
/**
*
* @author Gerson
*/
public class Main {
private static DeterminaMaiorMenorZN MyDeterminaMaiormenorZn;

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
String strNum1Zn, strNum2Zn, strNum3Zn, msgSaida;

// Entrada de dados ...
strNum1Zn = JOptionPane.showInputDialog("Digite o primeiro zn número");
strNum2Zn = JOptionPane.showInputDialog("Digite o segundo zn número");
strNum3Zn = JOptionPane.showInputDialog("Digite o terceiro zn número");
/**
* Instanciando um objeto cujo o tipo é a classe "Main".
* O construtor "Main()" retorna um referencia de memória
* para a variável "MyDeterminaMaiormenorZn"
*/
MyDeterminaMaiormenorZn = new DeterminaMaiorMenorZN();

// Atribuindo valor aos atributos
MyDeterminaMaiormenorZn.setNum1Zn(Double.parseDouble(strNum1Zn));
MyDeterminaMaiormenorZn.setNum2Zn(Double.parseDouble(strNum2Zn));
MyDeterminaMaiormenorZn.setNum3Zn(Double.parseDouble(strNum3Zn));
//PROCESSA a verificação para encontrar o maior e o menor valor
MyDeterminaMaiormenorZn.executaVerificacao();

// Saída de dados
JOptionPane.showMessageDialog(null, " Estação Zn - " +
MyDeterminaMaiormenorZn.getZnMsgSaida(), "www.estacaozn.blogspot.com",
JOptionPane.INFORMATION_MESSAGE);

// Finaliza programa
System.exit(0);
}

}


Agora sim podemos dizer que temos um programa em Java. Veja que na "public class Main {", aquele aspecto de código macarrônico sumiu. Logo, estamos mais perto da luz!


A seguir, veja abaixo, através da UML, como as classes codificadas se relacionam. Usei o Jude para elaborar um diagrama de classes que modelasse o algoritmo.


Na ilustração abaixo adaptei para o contexto Delphi o diagrama de Classes



Mas qual foi a causa da terceira modularização? Será que você conseguiu perceber? Está última modularização foi a que alcançou de fato o grau máximo de funcionalidade atômica para cada sub-rotina. No exemplo anterior, as sub-rotinas “EncontraMenor” e “EncontraMaior” além de determinarem o maior e o menor, cada uma respectivamente, elas no final ainda ficaram encarregadas de fornecer o output para o usuário. Elas convertem o valor e possuem como saída a mensagem pro usuário. Isso não é legal, cada uma delas está acumulando funções diferentes e esse tipo de deslize lógico é que acaba sendo o tempero das macarronadas mais substanciosas e pesadas. Então, recodificamos cada uma das sub-rotinas para que elas possuam apenas uma funcionalidade, apenas uma responsabilidade. E transferimos para o que chamamos de programa principal a responsabilidade de comunicar ao usuário o resultado. Assim estamos mais perto da Luz!!!


Conclusões

O primeiro objetivo que devemos desejar alcançar quando fazemos uma mudularização é desenvolver um módulo com uma funcionalidade única irredutível, atômica. Quando você consegue isso está mais perto da luz, ponto pra vc.

O segundo objetivo é tornar esse módulo, que possui uma, apenas uma, funcionalidade única irredutível, o mais coeso possível e menos acoplado possível. Ou seja, conseguir fazer dele uma caixa preta. Quando você consegue isso está mais perto da luz, ponto pra vc.

O terceiro objetivo é conseguir o reaproveitamento da sub-rotina. Esse objetivo é ocupa um plano secundário em relação aos dois primeiros. O reaproveitamento de um módulo só traz benefícios efetivamente quando ele conseguiu antes atingir os dois anteriormente descritos. Do contrário ele será prejudicial, visto que o acoplamento gerado pelo reaproveitamento tornará seu sistema sensível a mudanças. Conseqüentemente, o processo de manutenção tanto evolutiva, quanto corretiva, será extremamente custoso. Em muitos casos tornando-se até mesmo inviável. Portanto, a argumentação, que defende a idéia de que a modularização não deve ser feita quando o reaproveitamento não será necessário, não se sustenta.

Concluindo, numa análise final, esse artigo também serviu para uma demonstração e entendimento da relação existente entre uma implementação OO e uma implementação estruturada. Aliais, a relação entre esses dois paradigmas de programação tem ganhado uma atenção especial aqui no estação ZN. Você pode ter certeza que isso não se deve ao acaso. Neste artigo podemos ver que não existe uma dualidade antagonistica entre esses paradigmas. Na minha opinião, não existe OO sem estruturação. Ou seja, um programador ou analista só fará bem OO se ele tiver muito bem consolidados os conceitos da estruturação. A conveniência de usar um ou outro vai depender de algumas variáveis, como por exemplo: A tecnologia que você estiver usando, a metodologia de engenharia adotada no projeto, ou a formação e cultura da equipe. Por exemplo, se você pretende conjugar estruturação e UML acho que encontrará alguma dificuldade para harmonizar o processo de analise com o de desenvolvimento. Presumo ... hehehhe!


Artigo completo (View Full Post)

 
BlogBlogs.Com.Br