Exemplo de refatoração de Delphi envolvendo controles e datamodules conscientes dos dados com acesso direto às tabelas DB

StackOverflow https://stackoverflow.com/questions/4051810

Pergunta

Estou tentando definir a melhor maneira de refatorar o projeto em que estou trabalhando.

Devido à falta de bom design, quase todo o projeto é composto de:

1) Formas que contêm lógica de negócios

2) Datamodules enormes (1 por formulário + alguns extras)

3) Algumas unidades que contêm código comum (bibliotecas)

Não há OOP (exceto algumas áreas pequenas), a reutilização do código é em um nível mínimo.

Um problema também é que os controles do DataWare são usados, por isso foi muito simples soltar muitos dados+fontes de dados nos datamodules e vincular diretamente ao banco de dados de uma maneira altamente acoplada.

Idealmente, gostaria de extrair classes, como Tcustomer, Temployee, para obter o encapsulamento do SO vantagem e possibilitar a criação de uma nova interface do usuário no futuro sem duplicar todo o código.

De qualquer forma, minha pergunta é: como posso continuar lidando com os controles da DataAware? Devo implementar uma função que retorne um conjunto de dados e vincula o datawarecomponent.dataSource ao resultado da função?

function TCustomer.LoadByID(aCustomerID: integer): TDataset

?

Foi útil?

Solução

Você está vinculado à arquitetura que seu aplicativo foi projetado. Não tente lutar contra isso. Deixe os controles conscientes dos dados fazerem o que são bons, sincronização de dados. Se seus controles já estiverem vinculados às fontes de dados usando o DFM, não deve haver um problema.

O que você precisa para refatorar são todos os manipuladores de eventos que você anexou aos seus controles. Eu sugiro que você dê uma olhada no Controlador supervisor padronizar. Encontrei implementações de exemplo para:

Embora existam alguns exemplos de padrões arquitetônicos da interface do usuário em Delphi aqueles que são voltados para aplicações de mesa tendem a ser sobre o Vista passiva em vez de supervisionar o controlador. Então aqui está minha opinião sobre isso.

Você deseja começar a definir pelo menos uma interface para cada formulário em seu aplicativo. eu digo pelo menos um Porque algumas formas são complexas e podem precisar ser divididas em várias interfaces.

IProductView = interface
end;

Em seguida, peça ao seu formulário que o implemente.

TProductForm = class(TForm, IProductView)
...
end;

Em seguida, você precisará de um apresentador/controlador. Isso lidará com tudo, exceto a sincronização de dados.

TProductPresenter = class
private
  FView: IProductView;
public
  constructor Create(AView:IProductView);
end;

Crie um campo privado na sua classe de formulário e crie/livre o apresentador quando o formulário for criado/liberado. Se você usa o construtor/destruidor do formulário ou os eventos OnCreate/OnDestroy não importa muito.

TProductForm = class(TForm, IProductView)
private
  FPresenter: TProductPresenter;
public
  constructor Create;
...
end;

implementation
TProductForm.Create
begin
  FPresenter := TProductPresenter.Create(self);
end;

Agora, quando você precisa do formulário ou um de seus controles para responder a uma responsabilidade de um evento para o apresentador. Vamos supor que você precise verificar se o nome do produto usa capitalização adequada.

TProductForm.NameDBEditChange(Sender: TObject);
begin
  FPresenter.ValidateName;
end;

Em vez de passar no controle ou em sua propriedade de texto como um argumento, você expõe os dados como uma propriedade na interface ...

IProductView = interface
  function GetName:string;
  procedure SetName(Value: string);
  property Name: string read GetName write SetName;

... e implementar GetName e SetName No formulário.

TProductForm.GetName: string;
begin
  Result := NameDBEdit.Text;
end;

TProductForm.SetName(Value: string);
begin
  NameDBEdit.Text := Value;
end;

É importante expor os dados da forma mais simples possível. Você não deseja que o apresentador, dependendo do nome do produto que está sendo armazenado em um TDBEDIT. O apresentador deve ver apenas o que você permite explicitamente ver através da interface. O principal benefício disso é que você pode modificar o formulário o quanto quiser (ou substituí -lo inteiramente) e, desde que adere à interface, nenhuma alteração precisará ser feita ao apresentador.

Agora que toda a sua lógica de negócios foi transferida para o seu apresentador, ela se parecerá com uma classe de Deus. Seu próximo passo será refatorar essa lógica em classes apropriadas divididas por responsabilidade. Quando você chega a esse ponto, está em uma posição muito melhor para tentar um redesenho arquitetônico (se você ainda está considerando).

"Uau! Isso parece muito trabalho!" pode-se dizer. Você estaria certo (mas então sabia que seria muito trabalho antes de começar). Não precisa ser feito de uma só vez. Nenhuma dessas etapas está mudando o comportamento da lógica exatamente onde ocorre.

Vantagens

  • UI agora é fácil de modificar
  • A lógica de negócios pode ser mais facilmente testada isoladamente
  • Pode ser implementado incrementalmente

Desvantagens

  • É mais trabalho a princípio, embora isso seja compensado por um código mais sustentável posteriormente.
  • Não é adequado para todas as aplicações. Para pequenos projetos, a infraestrutura adicional pode não valer o esforço.

Outras referências

Outras dicas

Se não houver um bom design e nenhum OOP real no código, considerando sua complexidade, você deve primeiro começar criando um design descrevendo sua funcionalidade atual. Sim, isso significa que você estará ocupado escrevendo muita documentação no início. Mas permite dividir todo o projeto em peças lógicas/funcionais que você pode usar para se concentrar assim que essa documentação for concluída. Você pode refatorar cada parte separadamente, ou possivelmente reescrever essas peças até.
Projetos Este complexo nem sempre é prático para refatorar. Você deve retornar ao design original (criá -lo, pois não possui) e depois olhe para o seu código e considere o que é mais rápido: refatorar ou reescrever ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top