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!


Nenhum comentário:

Postar um comentário

 
BlogBlogs.Com.Br