quarta-feira, 10 de setembro de 2008

Jobim e Vinicius

Eu tive o privilégio de conhecer e conviver com personagens de extrema importância dentro do cenário da música popular brasileira. Ouvi as histórias, famosas, da bossa nova por seus próprios protagonistas.
A sabedoria do Gato, grande mestre, saudoso, Durval Ferreira. A genialidade bem humorada do cordial João Donato. Carlos Lyra, o Shakespeare da MPB. Roberto Menescal, o mentor, dentre outros gigantes. Pelos quais tenho profunda admiração.
Embora não tenha sido possível conhecer o Tom nem o Vinicius pessoalmente, pude conhecê-los um pouco, de uma forma que considero especial, oque também entendo como privilégio, pois posso olhar dentro de sua obra.



Através dos olhos desses amigos, professores. Neste artigo, trago minha leitura de um momento, de um acontecimento: Tom e Vinicius

O Que Tinha de Ser




OBS: Na partitura acima, eu não transcrevi a interpretação da Elis.




Artigo completo (View Full Post)

Usando Sibelius - Editor de Partitura ... Aos Nossos Filhos (Ivan Lins)

Perdoem a cara amarrada,
Perdoem a falta de abraço .... 




Apara adicionar uma cifra no Sibelius pressione Ctrl + K, o cursor vai ficar ativado (Azul), então basta clickcar sobre o compasso o qual receberá a cifra. Agora digite normalmente a cifra. Pronto!

Para deletar, excluir, um compasso: Com o Ctrl pressionado, click sobre o compasso a ser excluido. Ele vai ficar selecionado com uma dupla borda, agora basta pressionar “Delete”. 

Para deletar vários compassos de uma só vez: Com o Ctrl pressionado, click sobre um dos compassos a serem excluidos. Ele vai ficar selecionado com uma dupla borda, em seguida pressione o Shift, o mantendo pressionado, para selecionar os demais compassos.

Para determinar a quantidade de compassos numa linha: Click sobre a barra de compasso final do último compasso que você deseja que fique na linha, em seguida pressione “Enter”.
Veja a ilustração abaixo:



Na imagem seguinte, clickei sobre a barra de compasso final do último compasso que você eu quero que fique na linha, no meu caso o quarto compasso da primeira linha. Em seguida, pressione “Enter”.



Perdoem a falta de espaço,
Os dias eram assim...



Perdoem por tantos perigos,
Perdoem a falta de abrigo,
Perdoem a falta de amigos,
Os dias eram assim...


Como ilustração das funcionalidades vistas no Sibelius



Segue partitura com a cifragem da minha interpretação dessa obra prima do Ivan e do Vitor. Mudei um pouco a harmonia em alguns trechos (pra variar um pouco). Alterei também o andamento, na versão que linkei com o MP3 tube o Ivan gravou um rubato em 6/8 (me parece ...). Escrevi em 4/4 ...

Aos Nossos Filhos – (Ivan Lins e Vitor Martins)



Para quem não conhece .... segue versão com o próprio

 Ivan Lins - Aos Nossos Filhos

Artigo completo (View Full Post)

terça-feira, 9 de setembro de 2008

Cliente WebService – Delphi7 & Servidor Webservice BDS2006

Continuando, sobre WebServices, construiremos o cliente que consumirá o serviço que criamos no artigo “Webservice no BDS2006”.
No Delphi 7 inicie um novo projeto: Menu File ► New ► Application. Em seguida vou adicionar um TButton, um TlistBox no Form1.



Importando a WSDL

Próximo passo, importar a interface do serviço. Para isso, no browser digite a url para acessarmos o WebService. Usaremos o serviço contruido no artigo anterior, portanto digite na barra de endereços do browser: http://localhost/wsshowmethemoneyzn/
Click no link “IZnShowMeTheMoney [WSDL]”, a página que será exibida é o XML que define as especificações da interface do serviso “ZnShowMeTheMoney”. Salve esta página.





Voltando ao Delphi, no menu Menu File ► New ► Other, na aba WebServices selecione “WSDL Importer”.


Selecione o arquivo que acabamos de salvar, o arquivo XML que especifica a interface do serviço: “IZnShowMeTheMoney.xml”.



Em seguida click em “Next”, Tchan ... Tchan ... Tchammm ..!!!! Você acabou de importar a WSDL para sua aplicação cliente. Pode ficar emocionado amigo, agora você faz parte de um seleto grupo de indivíduos que ultrapassaram a fronteira do B2C (Businesses to Consumer) para o B2B (Businesses to Businesses). Parabéns! Em seguida, ao clicar em “Finish”, prosseguiremos salvando a nova unit, resultante da importação que acabamos de fazer, IZnShowMeTheMoney1.pas. Então, codificaremos a funcionalidade que evocará o serviço “IznShowMeTheMoney”.



Na unit1 farei uses da unit “IZnShowMeTheMoney1.pas”, Alt + F11. Falta ainda adicionar um THTTPRio (Palheta WebServices)





Na propriedade URL do HTTPRIO1 digite a url da interface, WSDL, do serviço “IznShowMeTheMoney” trocando o “/wsdl” para “/soap”. Exemplo: http://localhost/wsshowmethemoneyzn/PrjZNShowMoney.dll/soap/IZnShowMeTheMoney

No evento “OnClick” do Button1 digite conforme iluistrado abaixo:


procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add((HTTPRIO1 as IZnShowMeTheMoney).ZnShowMeTheMoney);
end;


Asseguir código completo da Unit1:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, InvokeRegistry, Rio, SOAPHTTPClient;

type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
HTTPRIO1: THTTPRIO;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

uses IZnShowMeTheMoney1, Math;

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add((HTTPRIO1 as IZnShowMeTheMoney).ZnShowMeTheMoney);
end;

end.




Conclusões
Para consumir um WebService é preciso importar a interface so serviço para o programa cliente.
O Fato de usar um WebService não garante a interoperabilidade entre dois sistemas. É muito importante garantir que o tipo de dado da saída do seu serviço seja suportado pela tecnologia usada pelo cliente.
No nosso exemplo pudemos observar que um servidor Werbservice construido em BDS2006 pode ser consumido por um cliente desenvolvido em Delphi 7. O que já era de se esperar, contudo este pequeno exemplo não pode garantir que isso é válido para qualquer outro caso.

Artigo completo (View Full Post)

Deploy de uma DLL ISAPI no ISS 5

Primeiro precisamos, no IIS criar um diretório: Criando um diretório virtual ...

No Internet Information Service (da MS), selecione na treeview a direita o nó “Site da Web padrão” (“Default Web Site”).



No menu popup da treeview (botão direito do mouse) selecione: Novo ►Diretório Virtual. Em seguida faremos amgulas configurações dos diálogos seguintes:



No primeiro diálogo, simplesmente click em avançar.



No segundo definiremos o nome do diretório virtual. Um alias, nome pelo qual evocaremos o serviço via browser: Exemplo: http://localhost/MeuDiretorioVirtual_BlaBla.



Para este exemplo vou definir como alias “WsShowMeTheMoneyZn”. Após digitar o alias click “Avançar”.



Agora aponte o diretório virtual que estamos criando para uma diretório físico, real, existente na sua máquina.






No diálogo seguinte, “Permissões de acesso”, obrigatóriamente precisamos permitir a execução de script ISAPI (no servidor, obiviamente). Marque a opção conforme ilustrado na imagem abaixo:



Pronto! Ao concluirmos terminamos a primeira etapa que a criação do diretório virtual. Click em “Concluir” para passarmos a segunda etapa.



Veja nosso novo diretório virtual, o qual proverá acesso ao nosso serviço via http;


Configurações finais para o IIS executar a DLL ISAPI

Com o botão direito do mouse sobre “WsShowMeTheMoneyZn”, o diretório virtual que acabamos de criar, selecione “Propriedades”



Precisamos definir qual arquivo vai ser executado pelo IIS quando um cliente via browser requisitar a url cujo endereço é o nosso diretório virtual.



Na aba documentos, conforme ilustrado anteriormente, click em “Adicionar ...” e digite o nome completo, com a extensão e tudo, da dll ISAP. Neste caso particular, considerando que este artigo e complemento de “Webservice no BDS2006” digitarei o nome da “DLL” gerada no referido artigo: “PrjZNShowMoney.dll”



Click em “Ok” para terminar a configuração. Para testar, no browser digite:
http://localhost/wsshowmethemoneyzn/


Artigo completo (View Full Post)

segunda-feira, 8 de setembro de 2008

Webservice no BDS2006

Observamos que o assunto "WebService em Delphi" tem tido muita procura aqui no blog. Por isso, pretendo produzir mais material sobre este tema. Contudo, o assunto é abrange um escopo bastante vasto, principalmente no que tange as questões práticas do desenvolvimento de serviços baseados em XML/SOAP. Podemos citar para exemplificar alguns temas sobre “WebService e Delphi”: Testar as versões mais recentes (inclusive o Tiburon – Delphi 2009), verificar incompatibilidades (se existirem), ou diferenças. Uma coisa interessante seria a integração com outras tecnologias (Java, C# e PHP, por exemplo). Outro ponto importante: Acesso e disponibilização de dados (um CRUD, talvez, usando como camada intermediária um aplicação servidora WS). Em fim, há bastante terreno para ser trabalhado.
Neste sentido, podemos eventualmente atender alguma questão pontual demandada pelos leitores. Coloque em forma de comentários sua demanda que na medida do possível teremos prazer em atendê-la. Algumas pessoas já solicitam nosso suporte, informalmente, via e-mail. Porém, seria melhor que além do e-mail o comentário sobre a demanda fosse registrado. Pois, dessa forma aproveitamos a resolução do seu problema para conteúdo do blog. Assim, outros que por ventura vierem até nós com problemas semelhantes possam compartilhar da solução sem gerar retrabalho para nós. Conseqüentemente, imagino que nosso conteúdo será mais aderente. Isso é o que de fato nos importa.

Iniciando um novo projeto

No BDS2006 no menu File ►New ► Other ► Delphi Projects ►WebServices, selecione “SOAP Server Application”. Em seguida uma série de configurações prévias serão feitas mediante alguns diálogos.



No diálogo seguinte selecione ISAPI/NSAPI Dynamic Link Library, e click em “OK”.



Click “Yes” para criar a interface do serviço (WSDL). Veja imagem abaixo:



No próximo diálogo definiremos o nome do serviço que estamos criando: “ZnShowMeTheMoney”, conforme ilustrado abaixo.



Pronto, temos um novo projeto! Estamos desenvolvendo uma aplicação servidora. Um WebService, veja as units que foram cridas na inicialização do nosso projeto:



A lógica sobre declarações nas units, num projeto WebService: Existe uma unit para declarações de interface e uma unit para as implementarmos o que declararemos na unit interface (neste caso temos: “ZnShowMeTheMoneyIntf”, interface. “ZnShowMeTheMoneyImpl”, implementação).

Na interface declararemos uma função. Digite conforme ilustrado abaixo:

  (* Declarando uma funcionalidade no serviço que estamos criando *)
  function ZnShowMeTheMoney: WideString; stdcall;

A seguir, veja como ficou a unit “ZnShowMeTheMoneyIntf”.
{ Invokable interface IZnShowMeTheMoney }

unit ZnShowMeTheMoneyIntf;

interface

uses InvokeRegistry, Types, XSBuiltIns;

type

  { Invokable interfaces must derive from IInvokable }
  IZnShowMeTheMoney = interface(IInvokable)
  ['{F002F904-9FD7-401D-80E2-037DFFAA4590}']

  { Methods of Invokable interface must not use the default }
  { calling convention; stdcall is recommended }
  (* Declarando uma funcionalidade no serviço que estamos criando *)
  function ZnShowMeTheMoney: WideString; stdcall;
end;

implementation

initialization
  { Invokable interfaces must be registered }
   InvRegistry.RegisterInterface(TypeInfo(IZnShowMeTheMoney));

end.


Agora para implementarmos iremos fazê-lo na unit “ZnShowMeTheMoneyImpl”. Digite conforme ilustrado no trecho de código asseguir:
type

  { TZnShowMeTheMoney }
  TZnShowMeTheMoney = class(TInvokableClass, IZnShowMeTheMoney)
  public
   (* Na unit de implementação precisamos digitar novamente a assinatura do
      método que declaramos na interface "ZnShowMeTheMoneyIntf" *)
     function ZnShowMeTheMoney: WideString; stdcall;
end;

implementation


Declare uma seção “uses” após a palavra reservada “implementation” e declare as bibliotecas: Math e SysUtils.

OBS: No BDS temos code insight para declaração de bibliotecas!!!



Vamos implementar o método declarado na seção public de “TZnShowMeTheMoney”.
  function TZnShowMeTheMoney.ZnShowMeTheMoney: WideString;
  const
    ZnMsgConst = 'Here is your Money, U$ %f! Do you can see him? look at the message ... ';
  var
    RandomValue: Double;
    RandomDiv: Integer;
  begin
    RandomValue := RandomRange(1, 10000);
    RandomDiv := RandomRange(1, 7);
    RandomValue :=  (RandomValue / RandomDiv);

     Result := Format(ZnMsgConst, [RandomValue]);
  end 


A função que acabamos de codificar, “ZnShowMeTheMoney”, é simplesmente um processamento dummy que retorna aleatoriamente dois valores, os quais são usados como operandos numa divisão cujo o resultado é formatado numa string e retornado na função.
Agora vamos salvar a aplicação, veja ilustração abaixo:




Para o nome do projeto vamos usar “PrjZNShowMoney.bdsproj”. A imagem seguinte mostra, o meu “Project Manager”, para que você possa compara a estrutura do seu projeto com o andamento do nosso exemplo.



Agora vamos publicar nosso serviço: Compile o projeto, em seguida faça o deploy da DLL, “PrjZNShowMoney.dll”, no IIS.

Criei um diretório virtual com alias de “WsShowMeTheMoneyZn”. Para testar, no browser digite: http://localhost/wsshowmethemoneyzn/

Click no link WSDL e você acessará a interface do serviço “IZnShowMeTheMoneyservice”, isso que você esta vendo é mais que uma página web comum.




Neste primeiro exemplo podemos concluir que o desenvolvimento em WS no BDS2006 é semelhante ao do Delphi 7.
É Muito rápido, intuitivo e amigável desenvolver serviços RPC baseados em SOAP/XML no DBS2006, desde que você conheça bem três conceitos:

1 - A estrutura de declarações no Delphi.

2 - Calling Conventions: Convenções de chamadas (traduziremos assim)- Quando declaramos procedimentos ou funções podemos definir, neste momento, a convenção de chamada através das diretivas: register, pascal, cdecl, stdcall, and safecall.
Por exemplo:
  function ZNFuncao(const Xzn, Yzn: Double): Double; cdecl;
  function ZNProcedimento(const Xzn, Yzn: Double; var AoutZn: Double); stdcall;

3- Sistemas distribuídos: Também chamado na literatura de objetos distribuídos.

Outros artigos sobre Webservice e Delphi

Artigo completo (View Full Post)

segunda-feira, 1 de setembro de 2008

Começaram os eventos de divulgação da mais nova versão do Delphi

A CodeGear irá realizar uma série de eventos gratuitos onde serão apresentadas as novas features incorporadas ao Delphi, versão intitulada de Delphi 2009.

Yes, temos Generics!!! Isso é muito bom, já devia estar na Delphi language faz empo. Antes tarde do que nunca.
Evolução do DataSnap!!! Ufa, chegou! O Malta estave falando sobre isso .... veja em.

Temos DER!!! Bem testaremos antes de emitir qualquer opinião. Contudo fico otimista e confiante em virtude dos seguintes pontos:
Primeiro, a agilidade e, a princípio, a economia de você ter na IDE uma boa ferramenta de modelagem. Mas tem que ser boa, tanto em termos de usabilidade, quanto de funcionalidade. Por exemplo: um “Complete compare” é sempre bom e etc
Segundo, o buraco gigante que as ferramentas de modelagem, como o Erwin (em virtude do preço e de deficiências de usabilidade), o MS Visio (Pela deficiência na padronização e ausência de funcionalidades importantes), o EA (Também com usabilidade pouco amigável e falha de padronização), deixam no mercado.

O Estação Zn esta torcendo, e estaremos presentes nos eventos!
Faça sua inscrição no site da CodeGear.
No Rio de Janeiro o evento esta previsto para o dia 11/09 no auditório do Jockey Clube, Av. Presidente Antônio Carlos, 501, décimo andar, Centro(Inscreva-se).

Artigo completo (View Full Post)

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