Padrão Builder (Builder Pattern)
Construa objetos de configuração ou de domínio complexos passo a passo com padrões, setters fluentes e validação em build().
Receita
let client = HttpClient::builder()
.timeout(Duration::from_secs(10))
.build()?;Quando usar isso: Muitos campos opcionais ou validação que devem ser executados uma vez na construção.
Exemplo de Trabalho
#[derive(Default)]
struct ConfigBuilder {
port: Option<u16>,
host: Option<String>,
}
impl ConfigBuilder {
pub fn port(mut self, port: u16) -> Self { self.port = Some(port); self }
pub fn host(mut self, host: impl Into<String>) -> Self { self.host = Some(host.into()); self }
pub fn build(self) -> Result<Config, &'static str> {
Ok(Config {
port: self.port.ok_or("port required")?,
host: self.host.unwrap_or_else(|| "localhost".into()),
})
}
}O que isso demonstra:
- Apenas
Configé público após a construção bem-sucedida - Padrões vivem no builder, não espalhados nos pontos de chamada
build()retornaResultpara erros de validação- Métodos encadeáveis que consomem
self
Mergulho Profundo
Use derive com typed-builder ou bon para structs grandes. Para clientes assíncronos, o builder pode produzir um Client que se conecta em build().await.
Armadilhas
- Builder exposto, mas campos da struct públicos - ignora a validação. Correção: campos privados no tipo de produto.
- Builder com muitas chamadas
clone- lento. Correção: usemut selfna cadeia sem clonar strings até obuild. - Campos opcionais infinitos sem documentação de padrões - confusão. Correção: documente os padrões no rustdoc.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
Config::from_env | Apps 12-factor | API de Biblioteca |
| Literal de Struct | ≤3 campos | Muitos campos opcionais |
serde + validate | Configuração baseada em arquivo | Construção programática |
FAQs
builder vs Default?
Default fornece um objeto vazio; o builder adiciona validação e configuração em estágios.
build assíncrono?
build(self) -> impl Future<Output = Result<Client>> para configuração de conexão.
campos obrigatórios?
Use Option no builder até build(); ou new(required) separado + setters opcionais.
integração com clap?
Achate os argumentos do clap no builder ou construa Config a partir das correspondências.
builders de teste?
Use ConfigBuilder::default().port(0).build().unwrap() em testes.
builder de typestate?
Separação de fases em tempo de compilação; veja o padrão typestate.
armadilhas do derive_builder?
Regenere em caso de alterações de campo; revise a superfície da API gerada.
builder imutável?
Use setters &mut self se o builder for compartilhado entre threads (raro).
build parcial?
Não exponha o produto semi-construído; apenas build() retorna o produto.
documentar ordem da cadeia?
Geralmente a ordem é independente; documente se os setters interagem.
Relacionados
- Padrão Typestate - builders em estágios
- Noções Básicas de Padrões Rust - visão geral
- Design de Configuração e Funcionalidades
- Melhores Práticas de Padrões Rust
Versões da Stack: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.