Table of Contents
Compreender o padrão de fábrica em Angular
As aplicações Angular modernas requerem frequentemente formulários que se adaptam a diferentes funções de utilizador, esquemas de dados ou ambientes de configuração. Criando manualmente [[FLT: 0]] instâncias para cada permutação leva a duplicar o código, frágil alternar casos e lógica de validação emaranhada. O Padrão de Fábrica aborda isto, fornecendo um mecanismo centralizado para produzir objetos de forma com base num tipo ou configuração definido. Em essência, a fábrica actua como um orquestrador de construção de formulários: aceita uma especificação (por exemplo, uma string, um enum ou um objeto de configuração) e devolve um totalmente inicializado] com os comandos, validadores e valores por omissão apropriados.
A fábrica encapsula a lógica de instanciação, de modo que os componentes não precisam mais saber qual classe de forma para instanciar ou como montar os controles. Esta separação de preocupações torna a base de código mais modular, testável e escalável — especialmente quando o número de tipos de forma cresce além de um punhado. O padrão se encaixa naturalmente no sistema de injeção de dependência Angular, permitindo que você registre funções de fábrica como provedores e injete-os onde necessário.
Por que usar o padrão de fábrica para formas dinâmicas?
Angular já fornece o para lidar com cenários de forma complexa, mas o padrão de fábrica elimina a caldeira procedimental que muitas vezes acompanha a criação de forma. Aqui estão as principais vantagens:
- Reduz duplicação de código. Em vez de repetir construções semelhantes entre componentes ou serviços, você centraliza a lógica em um método de fábrica. Cada tipo de formulário é construído por uma classe de construtor dedicado, então você escreve sua lógica apenas uma vez.
- Melhora a manutenção. Adicionar um novo tipo de formulário significa criar uma nova classe de construtor e registrá-la na fábrica. Nenhum componente existente precisa mudar, desde que solicite formulários por tipo.
- Permite configurações flexíveis de formulários. A fábrica pode aceitar parâmetros adicionais (por exemplo, permissões de usuário, localização ou sinalizadores de recursos) que influenciam os controles incluídos ou como eles são validados.
- Suporta interfaces dinâmicas de usuário. Quando o tipo de formulário é determinado em tempo de execução (por exemplo, a partir de um registro de banco de dados ou um parâmetro de rota), a fábrica torna trivial instanciar o correto na hora.
- Melhora a testabilidade. Cada construtor de formulários pode ser testado independentemente. A própria fábrica se torna um mapeamento simples que pode ser zombeado ou esboçado em testes de componentes.
Esses benefícios são especialmente valiosos em aplicações empresariais que devem suportar muitos fluxos de trabalho distintos, cada um com seu próprio conjunto de campos e regras de validação.
Etapas de Implementação Principais
Passo 1: Definir o tipo de formulário de enumeração e interfaces
Comece definindo um conjunto de tipos de formulários. Usar um enum evita erros de digitação e fornece um contrato claro:
export enum FormType {
Login = 'login',
Registration = 'registration',
Feedback = 'feedback',
Contact = 'contact'
}
Em seguida, defina uma interface que todos os construtores de formulários irão implementar. Isto garante que a fábrica pode tratá-los polimórficamente:
import { FormGroup } from '@angular/forms';
export interface FormBuilderInterface {
build(config?: any): FormGroup;
}
O parâmetro opcional permite que os construtores personalizem o formulário com base em dados de tempo de execução, como valores pré-preenchimento ou ajuste das regras de validação por função do usuário.
Passo 2: Criar Construtores de Formulários de Concreto
Cada construtor de concreto implementa e retorna um configurado corretamente . Por exemplo, um construtor de formulário de login pode ser assim:
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
export class LoginFormBuilder implements FormBuilderInterface {
private fb: FormBuilder;
constructor() {
this.fb = new FormBuilder();
}
build(): FormGroup {
return this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6)]],
rememberMe: [false]
});
}
}
Um construtor de formulários de registo poderá incluir controlos adicionais e validação inter-campo:
export class RegistrationFormBuilder implements FormBuilderInterface {
private fb: FormBuilder;
constructor() {
this.fb = new FormBuilder();
}
build(): FormGroup {
const form = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
confirmPassword: ['', Validators.required]
}, { validators: this.matchPasswords });
return form;
}
private matchPasswords(group: FormGroup): { [key: string]: any } | null {
const password = group.get('password')?.value;
const confirm = group.get('confirmPassword')?.value;
return password === confirm ? null : { mismatch: true };
}
}
Esta estrutura escala de forma limpa: cada construtor se concentra apenas nos detalhes de sua própria forma, e você pode reutilizar a lógica através da composição de construtores ou usando funções auxiliares.
Passo 3: Construir a classe de fábrica
A classe de fábrica é responsável por mapear um tipo de formulário para o construtor correspondente. Uma implementação simples usa uma instrução de switch ou um objeto de mapa:
import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormType } from './form-type.enum';
import { LoginFormBuilder } from './login-form.builder';
import { RegistrationFormBuilder } from './registration-form.builder';
import { FeedbackFormBuilder } from './feedback-form.builder';
@Injectable({ providedIn: 'root' })
export class FormFactory {
private builders = new Map<FormType, FormBuilderInterface>();
constructor() {
// Register builders
this.builders.set(FormType.Login, new LoginFormBuilder());
this.builders.set(FormType.Registration, new RegistrationFormBuilder());
this.builders.set(FormType.Feedback, new FeedbackFormBuilder());
}
createForm(type: FormType, config?: any): FormGroup {
const builder = this.builders.get(type);
if (!builder) {
throw new Error(`No builder registered for form type: ${type}`);
}
return builder.build(config);
}
}
O registro de construtores dentro do construtor é simples, mas para aplicações maiores você pode preferir usar injeção de dependência Angular para fornecer construtores. Essa abordagem é abordada mais tarde.
Passo 4: Use a fábrica em componentes
Com a fábrica no lugar, os componentes podem solicitar uma instância de formulário sem saber os detalhes de sua construção. Por exemplo, um componente que lida com vários tipos de formulário com base em um parâmetro de rota:
import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormFactory } from './form.factory';
import { FormType } from './form-type.enum';
@Component({
selector: 'app-dynamic-form',
template: `