E se fosse modularizado?

Como escrevi no artigo "Por que usar Interfaces?", oque pode ser mais interessante
que modificar a mesma rotina sem perder as caracteristicas iniciais e poder dar
a possibilidade dela se modificar mais a ponto de atender todos os casos que
possam existir, seria elas nao estarem dentro do executavel e so serem carregadas
no momento que fosse usar.

Para por a par quem nao leu o artigo que mencionei acima, a situacao e um calculo
de compras, que um cliente efetuou durante o mes no estabelecimento, onde criamos
uma classe onde passamos as comprar e ela me retorna o total, mas surge a nescessidade
de esta mesma classe tambem ter a possibilidade de calular as compras e as que
foram feitas ate o dia 10 de cada mes, conceder um desconto de 10%.

Bom, a coisa agora comeca a ficar mais interessante, para isso vamos usar uma
coisa muito pouco conhecida que e a BPL. Sabemos que e uma DLL modificada pela
Borland para uso do Delphi, legal, mas oque ela tem de especial que
uma DLL nao faz? Pois bem, alem do fato de nao precisar declarar os metodos
que estao dentro do BPL voce ainda tem um recurso bem interessante, que sao
as seoes "Inicialization" e "Finalization" que sao automaticamente chamadas
quando damos um "LoadPackage" nesse modulo on um "UnLoadPackage". Neste ponto
nos podemos enchergar a Instancia da nossa aplicaao e com um pouco de pensamento
logico podemos inserir a classe deste modulo dentro do Aplicativo sem que seja
nescessario o Aplicativo se preocupar com o processo.

Vamos criar uma organizacao como abaixo:
Aplicativo -> Nucleo.BPL <-+-> Modulo1.BPL
                           |-> Modulo2.BPL
                           +-> Modulo3.BPL

O que temos em comum em todo o processo e que o Nucleo.BPL e visto por todos os modulos
envolvidos no processo, e como esta dentro de um BPL esta Unit nao sera compilada
dentro do executavel, mas sim sera carregada no momento que o executavel for aberto,
mas nao ira carregar os modulos, apenas o Nucleo, ja os modulos carregaremos mais adiante
quando forem nescessarios.

Abaixo veremos a secao de tipos da Unit presente em Nucleo.BPL:


Type
  ICalculo = Interface
    procedure Somar(Valor: Real; Data: TDateTime);
    function Apurado: Real;
  end;

  TCalculo = Class(TInterfacedObject, ICalculo)
  public
    procedure Somar(Valor: Real; Data: TDateTime); virtual; abstract;
    function Apurado: Real; virtual; abstract;
  end;

  TFechamento = class
  public
    function SaldoCliente(Dataset: TDataset; Modulo: string): Real;
  end;

Aqui temos a Interface dos Objetos o esqueleto da classe com os seus metodos
como Abstract, assim nao precisamos declaralos, ja que esta classe nao sera
usada e so servira de estrutura para o delphi saber com oque ele estara lidando
e a mesma sera herdada pelos modulos e sim, la dentro entao implementada;
A Classe TFechamento  a unida coisa que a aplicacao vai realmente ver e ela
que fara o carregamento dos modulos, veja que ha ate um parametro para o nome
do modulo que ela vai operar.

function TFechamento.SaldoCliente(Dataset: TDataset; Modulo: string): Real;
var
  Hnd: Cardinal;
begin
  Result := 0;
  Hnd := LoadPackage(Modulo);
  try
    if not Assigned(fCalculo) then
      raise Exception.Create('Classe de calculo do saldo no foi carregada.');
    with Dataset do
    begin
      first;
      while not Eof do
      begin
        fCalculo.Somar(FieldByName('Valor').AsFloat, FieldByName('Data').asDateTime);
        Next;
      end;
      Result := fCalculo.Apurado;
    end;
  finally
    UnloadPackage(Hnd);
  end;
end;

Podemos ver aqui que o modulo e simplesmente carregado e foi colocada uma verificacao
para saber se este implementou a classe dentro de FCalculo. Feito isto, passamos a
enviar os dados para a classe e no final pegar o valor apurado.

Nos modulos existem 2 detalhes importantes, primeiramente no uses da unit principal
do modulo existe uma chamada para a Unit do Nucleo e para que esta nao seja compilada
dentro da BPL precisamos dizer que este modulo e dependente de um outro BPL, para isto
no fonte do DPK na seao "Required" adicionaremos Nucleo, com isto ele sabera que nao
precisa compilar este codigo, ficando assim dependente deste modulo, como explicado
acima eles se enxergarao mutuamente.

requires
  rtl,
  dbrtl,
  Nucleo;

Agora ja dentro da Unit do modulo definiremos a classe:

type
  TCalculoNormal = Class(TCalculo, ICalculo)
  private
    FTotal: Real;
  public
    constructor Create;
    procedure Somar(Valor: Real; Data: TDateTime); override;
    function Apurado: Real; override;
  end;

implementamos os metodos e em seguida adicionamos ao final do fonte as
diretival que farao a magica acontecer:

initialization
  fCalculo := TCalculoAlterado.Create;

finalization
  FreeAndNil(fCalculo);

Veja que como a Unit2 esta presente no "uses" deste modulo nos conseguimos
ver a variavel fCalculo e entao criar a classe nela.
E no momento de descarregar o Modulo entao e limpa a variavel.

Vejamos agora o codigo que foi implementado no executavel para que este
carregasse Nucleo.BPL:

uses Unit2;

procedure TForm1.Button1Click(Sender: TObject);
var
  fFechamento: TFechamento;
begin
  fFechamento := TFechamento.Create;
  Label2.Caption :=  'Saldo: '+FormatFloat('#0.00', fFechamento.SaldoCliente(ClientDataSet1, Edit1.Text));
  FreeAndNil(fFechamento);
end;

Nele tambem na diretiva "uses" existe a Unit do Nucleo e neste caso tambem precisamos
dizer ao executavel que este codigo sera externo e que ele nao precisa compila-lo
dentro do executavel, para isto, abrimos as opcoes do projeto e na Guia Packages
Assinalamos o Item "Build with runtime Package" e no campo colocamos apenas "Nucleo"
assim tambem criaremos uma dependencia de Nucleo no executavel, e como ja dito,
todos envolvidos no processo verao Nucleo e este se tornara o centro de tudo.

Agora vendo o processo desenvolvido, fica mais claro o porque do Nucleo.BPL e como
este faz o carregamento dos modulos e como fica transparente o processo, pois nao
importa o quao grande e o modulo, este sera descarregado ao final do processo
liberando memoria e dando espaco para outros modulos serem carregados, tornando
sua aplicacao rapida, esperta, pois pode facilmente alterar a maneira com
que as coisas sao processadas e o mais lindo de tudo que sua aplicacao pode receber
versoes em partes, nao precisando enviar todo o sistema para um cliente no momento
de implementar uma nova rotina ou corrigir algo para um fim especifico.

Ja trabalhei em aplicativos genericos onde um simples executavel de poucos KBytes
gerenciava todo um sistema configuravel de modulos interligados e que podia de maneira
transparente rodar em partes e ser adquirido pelos clientes pedao-a-pedao.

Tanto os fontes aqui mencionados como um projeto completo com toda a estrutura mencionada
neste artigo, pode ser baixado na area de Downloads do Projeto Sultan no endereco:
www.welter.pro.br/sultan

Um grande abrao a todos e at o prximo artigo.

Marcelo Welter
Coodenador do Projeto Sultan
http://www.welter.pro.br/sultan


