domingo, 24 de agosto de 2008

Definido Parâmetros com valor default

Podemos definir argumentos de sub-rotinas possuindo valores pré-definidos. Esse recurso, os parâmetros de valor default, foi introduzidos no Delphi na versão 4. Desde então os progrmadores Delphi desfrutaram da capacidade de fornecer um valor default para um parâmetro de procedimento ou função sem a obrigatoriedade de passar esse parâmetro quando a rotina é chamada.
Para declarar um procedimento ou função que contenha parâmetros de valor default, coloque um sinal de igualdade e o valor default depois do tipo de parâmetro, como mostrado no exemplo a seguir:

procedimento EstacaoZNDefaultTeste(const TextValue: string; NumValue: Integer = 0);


Veja que é possível chamar o procedimento “EstacaoZNDefaultTeste ( )” de duas formas:

Uma delas, digamos que seja a primeira, você pode atribuir valor para ambos os parâmetros:

EstacaoZNDefaultTeste (‘hello ZN World’, 22);

Outra forma, digamos seja a segunda, você pode atribuir apenas o parâmetro “TextValue” e usar o valor default para “NumValue”:

EstacaoZNDefaultTeste (‘Hello Zn Landjah!!’); // valor default será usado pelo compilador para NumValue.

Devemos atender ao seguintes pontos para respeitar regras ao usar parâmetros (argumentos) de valor default:
1 - Os parâmetros com valores default devem aparecer no final da lista de parâmetros.
2 - Os parâmetros sem valores default não devem vir depois dos parâmetros com valores default em uma lista de parâmetros da função ou procedimento.
3 - Os parâmetros de valor default devem ser de um tipo ordinal, ponteiro ou conjunto.
4 - Os parâmetros de valor default devem ser passados por valor ou como constante. Eles não devem ser parâmetros não-tipificados ou de referência (out).

Um dos maiores benefícios dos parâmetros de valor default é poder criar versões mais diferentes de funcionalidades (funções e procedimentos) pré-existentes sem sacrificar a compatibilidade com versões anteriores. Ou seja, é possível durante a manutenção de um sistema recodificar determinada função sem sofrer reflexos am partes antigas do sistema definindo o novo parâmetro com valor default. Isso lhe poupará de fazer refactoring no sistema todo.


Artigo completo (View Full Post)

domingo, 10 de agosto de 2008

O princípio da caixa preta

Caixa Preta: O segundo principal objetivo que devemos buscar ao construir sub-rotinas é o comportamento de uma caixa preta. O mundo externo a caixa preta não conhece o que existe dentro dela, não sabe como ela realiza uma determinada tarefa. O mundo externo sabe apenas o que ela é capaz de fazer. Logo, considerando esse raciocínio é correto afirmar que: Uma sub-rotina deve ser como uma Caixa Preta, onde entram dados que serão processados (veja seobre parâmetros em) objetivando a obtenção de um valor de retorno específico, o qual atenderá alguma demanda do usuário.


A síndrome da fobia da Caixa Preta

Existe um tipo de profissional de TI que não se constrange em demonstrar seu incômodo quando estão trabalhando em programas muito modularizados. Eles reclamam do fato da falta de visibilidade quando uma rotina chama outra sub-rotina, ou várias. Será que ele não sabe que o objetivo é justamente esse? Algumas vezes não resisti e perguntei: Qual o problema no fato de determinada tarefa estar sendo realizada por uma dun-rotina, sedo que para ver o que ela faz basta debuggar fazendo um trace? A resposta em todas as vezes foi: “Não tenho certeza sobre o que a sub-rotina faz ...” . Para mim, fica parecendo que no fundo eles tem medo da caixa preta ... hehehheh. E conhecido que o ser humano teme o desconhecido, mas espera um pouco, amigo!?!?!??! Fala sério! Vc ta com medinho da caixa preta 02?
Esses programadores são conhecidos como “Jaspion”. Porque, no menor sinal de dificuldade apelam pro gigante guerreiro
Daileon sem o menor pudor. Seus códigos são verdadeiros gigantes muilti-funcionais. A rotina do cara faz de tudo, se bobear até serve cafezinho. Cruz credo! Eu já vi um Jaspion legitimo justificar-se que tinha ficado grande pois os trechos passiveis de modularização só seriam chamados apenas um vez, portanto, segundo ele, não deviam ser modularizados. Conclusão, o código do cara ficou parecendo um miojo bizonho, grudento e nojento.
Fico pensando quais seriam as causas para tanto medo de caixa preta. Será que é porque não conhecem o conceito? Bem, todas as vezes que perguntei a resposta foi: “Conheço, claro!”. Mas, não parece tão claro. O Jaspion só demonstra ter fé no código escrito por ele. Que irônico .... heheh!!!! Será que é arrogância, pura e simplesmente? Provavelmente são as duas coisas, pois não existe arrogância sem ignorância. Bem, posso não ter a resposta para essa questão, mas creio que ficará difícil negar que os Jaspoins têm medo da caixa preta.




Artigo completo (View Full Post)

Sub-Rotina - Programação

Comumente chamamos as sub-rotinas de “Procedimentos” (procedure) ou “Funções” (function). Podemos entendê-las como um trecho de programa escrito separadamente. Como conseqüência temos um trecho menor de código que executa uma única ação específica, isso facilita o entendimento (interpretação) aumentando, portanto a manutenibilidade do código.
Logo, uma sub-rotina pode ser usada em várias partes do sistema, dessa maneira podemos ter aproveitamento em diversos momentos diferentes de uma determinada ação, com a vantagem de que o gerenciamento da lógica dessa ação estar centralizado. Além de poder ser usada em várias partes do programa, a mesma sub-rotina pode, e deve, ser reaproveitada em outros sistemas ou programas. Em reflexo do reaproveitamento, devemos pensar no acoplamento que isso gera. Por isso, é muito importante estar atento e obstinado em alcançar um alto grau de COESÃO para a sub-rotina que estamos codificando.
Um ponto muito sensível nesta abordagem é que geralmente as variáveis que uma sub-rotina vai usar quase sempre são as variáveis do programa que a chamou. Isso é um grau de acoplamento que devemos evitar a todo custo. Devemos criar nossas sub-rotinas com argumentos. Eles são os parâmetros, através deles a sub-rotina pode receber e retornar valores garantindo uma comunicação entre ela e o mundo externo. Ou seja, o programa que a chamou, com uma baixo grau de acoplamento e um alto grau de COESÃO. Ela deve funcionar como uma caixa preta (Wikipédia).
Parâmetros – São os argumentos da sub-rotina. Seguindo a linha de raciocínio acima, os parâmetros são a comunicação da sub-rotina com os demais módulos que a chamarão em algum momento. Podemos entendê-los como a porta de entrada e a porta de saída da Caixa Preta.
Portanto, uma “function” ou “procedure” (em basic “Sub”), sub-rotinas que são, podem receber um conjunto de dados, que serão processados para um objetivo final. Entretanto, no momento de se declarar a sub-rotina é necessário que o programador defina quais, de que tipo, e quantas serão as entradas e saídas necessárias para que a mesma funcione corretamente. Ou seja, podemos e devemos declarar quem são os parâmetros de entrada, quem são os de saída. Podemos também definir valores default para alguns argumentos.

procedure SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean = False);

implementation

procedure TManagerGridZn.SetPopupMenu(const Value: TPopupMenu;
const nAllowCreate: Boolean);
begin
if (FPopupMenu = Value) and (Value <> nil) then Exit;

(* "nAllowCreate" define se o popup menu será sempre criado.
Considerando o caso de a mesma instância da classe manipular,
alternadamente, vários DBGrids que compartilham o mesmo popup menu. *)
If not Assigned(Value) or (nAllowCreate) then
begin
FPopupMenu := TPopupMenu.Create(Self);
FGrid.PopupMenu := FPopupMenu;
(* Avisa a classe que o popup menu foi criado *)
FIsPopupExistent := peInternalCreated;
end
else
begin
FPopupMenu := Value;
(* Avisa a classe que o popup menu já existia,
portanto possui itens. Ele foi associado com esses itens *)
FIsPopupExistent := peExternalAssociation;
end;

(* notifica a classe que o popup menu foi desassociado *)
if FPopupMenu <> nil then
FPopupMenu.FreeNotification(Self);
end;


O exemplo acima refere-se a um trecho de código usado nos artigos Construção de Componentes - VI e Construção de Componentes V a sub-rotina em questão trata da construção dinâmica de um Popup menu num DBGrid. Os valores atribuídos ao campo “FIsPopupExistent” é um tipo que criei para controlar se o Grid já possuía um menu Popup ou não.

 
TPopupExistent = (peExternalAssociation, peInternalCreated, peInexistent);


O argumento "nAllowCreate" possui um valor default definido igual a false, veja na linha 02. A Palavra resrvada "const" indica que é um parâmetro de entrada. Ou seja, a presença da palvra reservada "const" inica que "nAllowCreate" é uma porta de entrada da caixa preta. Para definir o parämetro de saída devemos usar a palavra reservada "var" antes do identificador.


Veja mais sobre o assunto em "Modularização em Programação: Coesão X Acoplamento, OO X Estruturação, Portugol X UML - a partir de um algoritmo simples".

Artigo completo (View Full Post)

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