Clique para saber mais...
  Home     Download     Produtos / Cursos     Revista     Vídeo Aulas     Fórum     Contato   Clique aqui para logar | 20 de Julho de 2026
  Login

Codinome
Senha
Salvar informações

 Esqueci minha senha
 Novo Cadastro

  Usuários
38 Usuários Online

  Revista ActiveDelphi
 Assine Já!
 Edições
 Sobre a Revista

  Conteúdo
 Apostilas
 Artigos
 Componentes
 Dicas
 News
 Programas / Exemplos
 Vídeo Aulas

  Serviços
 Active News
 Fórum
 Produtos / Cursos

  Outros
 Colunistas
 Contato
 Top 10

  Publicidade

  [Artigos]  E se fosse modularizado?
Publicado por welter : Quarta, Setembro 22, 2004 - 11:19 GMT-3 (6677 leituras)
Comentários 1 Comentário   Enviar esta notícia a um amigo Enviar para um amigo   Versão para Impressão Versão para impressão
Administrador Como escrevi no artigo "Por que Interfaces?", o que pode ser mais interessante que modificar a mesma rotina sem perder as características iniciais e poder dar a possibilidade dela se modificar mais a ponto de atender todos os casos que possam existir. Pois seria não estarem dentro do executável e só serem carregadas no momento que fosse usar.
Para quem não leu o artigo que mencionei acima, a situação e um calculo de compras, que um cliente efetuou durante o mês no estabelecimento, onde criamos uma classe onde passamos as comprar e ela me retorna o total, mas surge à necessidade de esta mesma classe também ter a possibilidade de calcular as compras e as que foram feitas ate o dia 10 de cada mês, conceder um desconto de 10%.

Bom, a coisa agora começa 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 o que ela tem de especial que uma DLL não faz? Pois bem, alem do fato de não precisar declarar os métodos que estão dentro do BPL você ainda tem um recurso bem interessante, que são as seções "Inicialization" e "Finalization" que são automaticamente chamadas quando damos um "Loadpackage" nesse modulo ou um "Unloadpackage". Neste ponto nos podemos enxergar a Instancia da nossa aplicação e com um pouco de pensamento lógico podemos inserir a classe deste modulo dentro do Aplicativo sem que seja necessário o Aplicativo se preocupar com o processo.

Vamos criar uma organização 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 módulos envolvidos no processo, e como esta dentro de um BPL esta Unit não será compilada dentro do executável, mas sim será carregada no momento que o executável for aberto, mas não ira carregar os módulos, apenas o Nucleo, já os módulos carregaremos mais adiante quando forem necessários.

Abaixo veremos a seção 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 métodos como Abstract, sendo assim não será preciso declará-los, já que esta classe não será usada e só servira de estrutura para o delphi saber com o que ele estará lidando e a mesma será herdada pelos módulos e nestes então será implementada.
A Classe TFechamento é a unida coisa que a aplicação vai realmente ver e ela que fará o carregamento dos módulos, veja que ha. ate um parâmetro 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 não 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;
end;
Podemos ver aqui que o modulo e simplesmente carregado e foi colocada uma verificação 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 módulos existem dois detalhes importantes, primeiramente no uses da unit principal do modulo existe uma chamada para a Unit do Nucleo e para que esta não seja compilada dentro da BPL precisamos dizer que este modulo e dependente de um outro BPL, para isto na fonte do DPK na seção "Required" iremos adicionar "Nucleo", com isto ele saberá que não precisa compilar este código, ficando assim dependente deste modulo, como explicado acima eles se enxergarão mutuamente.

requires
   rtl,
   dbrtl,
   Nucleo;
Agora já 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 métodos e em seguida adicionamos ao final da fonte as diretivas que farão à mágica acontecer:

initialization
   fCalculo := TCalculoAlterado.Create;
finalization
   FreeAndNil(fCalculo);
Veja que como a "Unit2" esta presente no "uses" deste modulo    nos conseguimos
   ver a variável fCalculo e então criar a classe nela.
   E no momento de descarregar o Modulo então e limpa a variável.

Vejamos agora o código que foi implementado no executável 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 também na diretiva "uses" existe a Unit do Nucleo e neste caso também precisamos dizer ao executável que este código será externo e que ele não será preciso compilar ele dentro do executável, para isto, abrimos as opções do projeto e na Guia Packages Assinalamos o Item "Build with runtime Package" e no campo colocamos apenas "Nucleo" assim também criaremos uma dependência de Nucleo no executável, e como já dito, todos envolvidos no processo verão Nucleo e este se tornara o centro de tudo. Agora vendo o processo desenvolvido, fica mais claro o porquê do Nucleo.BPL e como este faz o carregamento dos módulos e como fica transparente o processo, pois não importa o quão grande e o modulo, este será descarregado ao final do processo liberando memória e dando espaço para outros módulos serem carregados, tornando sua aplicação rápida, esperta, pois pode facilmente alterar a maneira com que as coisas são processadas e o mais lindo de tudo que sua aplicação pode receber versões em partes, não precisando enviar todo o sistema para um cliente no momento de implementar uma nova rotina ou corrigir algo para um fim especifico. Já trabalhei em aplicativos genéricos onde um simples executável de poucos Kbytes gerenciava todo um sistema configurável de módulos interligados e que podia de maneira transparente rodar em partes e ser adquirido pelos clientes conforme for preciso.

Arquivos do Artigo

Um grande abraço a todos e até o próximo artigo.

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



Comentários Comentários
   Ordem:  
Comentários pertencem aos seus respectivos autores. Não somos responsáveis pelo seus conteúdos.


por: Visitante : Fev 09, 2005 - 06:18
como crio uma bpl??
  Edição 112

Revista ActiveDelphi

  50 Programas Fontes


  Produtos

Conheça Nossos Produtos

Copyright© 2001-2016 – Active Delphi – Todos os direitos reservados