Builder — fundamentos do padrão builder no desenvolvimento móvel

Autor: IT Sectr Publicado: 2026-02-17 Tempo de leitura: 7 min

Builder — um padrão de criação que permite criar objetos complexos passo a passo. Diferente de um construtor com uma dúzia de parâmetros, o Builder monta um objeto através de uma cadeia de chamadas, cada uma configurando um campo. O padrão é especialmente útil para objetos com muitos parâmetros opcionais: configuração de cliente de rede, ajustes de banco de dados, construtores de alertas e navegação. Mais informações em Refactoring Guru: Builder.

Pontos principais

  • Builder — construção passo a passo de objetos separando processo e resultado
  • Fluent interface — cadeia de chamadas set()/with() para configuração conveniente
  • Imutabilidade — Builder cria um objeto pronto que não requer setters
  • Compatibilidade retroativa — novos campos podem ser adicionados ao Builder sem quebrar clientes
  • Kotlin DSL vs Builder — Kotlin oferece type-safe builders como alternativa

O que é Builder: a essência do padrão construtor?

Builder — um padrão criacional GoF que separa a construção de um objeto complexo de sua representação. O mesmo processo de construção pode criar diferentes representações. Builder é útil quando um objeto tem muitos parâmetros opcionais e um construtor com dez campos é ilegível e inflexível. O padrão também resolve o antipadrão Telescoping Constructor, onde o número de sobrecargas do construtor cresce exponencialmente.

Estrutura do Builder inclui uma classe interna estática Builder com campos espelhando os campos da classe principal. Cada set-método retorna Builder (this) para encadeamento fluido. O método final build() cria o objeto alvo passando os valores dos campos para um construtor privado. A classe principal tem um construtor privado que aceita um Builder. Cliente: Object.builder().setField1(val1).setField2(val2).build().

Quando usar Builder — objetos com 5+ campos onde apenas 2-3 são obrigatórios. Objetos de configuração (RequestConfig, DatabaseConfig). Objetos com lógica complexa de validação durante a criação. Objetos que devem ser imutáveis após a criação. No Android, Builder é ativamente usado no SDK: AlertDialog.Builder, Retrofit.Builder, OkHttpClient.Builder, NotificationCompat.Builder.

Builder em Kotlin: implementação clássica e DSL

Builder em Kotlin tem duas abordagens: Builder clássico estilo Java (através de uma classe aninhada) e Builder DSL estilo Kotlin (através de uma lambda com receptor). O Builder estilo Java é preferível para compatibilidade com Android e quando usado com código Java. O DSL builder é a forma idiomática do Kotlin: uma função aceita uma lambda dentro da qual this é o contexto Builder onde campos podem ser atribuídos diretamente.

kotlin
// Builder clássico
data class HttpConfig private constructor(
    val baseUrl: String,
    val timeout: Long = 30_000,
    val retries: Int = 3,
    val headers: Map<String, String> = emptyMap()
) {
    class Builder {
        private var baseUrl: String = ""
        private var timeout: Long = 30_000
        private var retries: Int = 3
        private var headers: MutableMap<String, String> = mutableMapOf()

        fun baseUrl(url: String) = apply { this.baseUrl = url }
        fun timeout(ms: Long) = apply { this.timeout = ms }
        fun retries(n: Int) = apply { this.retries = n }
        fun header(key: String, value: String) = apply { headers[key] = value }

        fun build(): HttpConfig {
            require(baseUrl.isNotBlank()) { "baseUrl is required" }
            return HttpConfig(baseUrl, timeout, retries, headers)
        }
    }
}

// Uso
val config = HttpConfig.Builder()
    .baseUrl("https://api.example.com")
    .timeout(15_000)
    .header("Authorization", "Bearer token")
    .build()

Kotlin DSL builder — uma alternativa sem classe aninhada. Uma função builder aceita uma lambda no contexto de um objeto construtor. Isto é idiomático para Kotlin e não requer write-fields. DSL builders são ativamente usados no Ktor Client, kotlinx.serialization, Compose (Modifier). O DSL builder é incompatível com Java e não é adequado para bibliotecas com API Java.

Builder em Swift: result builders e cadeias

Builder em Swift — Swift não tem um padrão Builder embutido, mas a interface fluida é facilmente implementada através de métodos que retornam Self. Cada método configura uma propriedade e retorna self. Diferente do Kotlin, Swift não requer uma classe Builder separada — você pode retornar o próprio objeto se ele for mutável durante a montagem. Para objetos imutáveis, uma classe Builder aninhada é usada de forma similar ao Kotlin.

swift
struct NetworkRequest {
    let url: String
    let method: HTTPMethod
    let headers: [String: String]
    let body: Data?
    let timeout: TimeInterval

    final class Builder {
        private var url: String = ""
        private var method: HTTPMethod = .get
        private var headers: [String: String] = [:]
        private var body: Data? = nil
        private var timeout: TimeInterval = 30

        func withURL(_: String) -> Self { /* self */ }
        func withMethod(_: HTTPMethod) -> Self { /* self */ }
        func withHeader(key: String, value: String) -> Self { /* self */ }
        func withBody(_: Data) -> Self { /* self */ }
        func withTimeout(_: TimeInterval) -> Self { /* self */ }

        func build() throws -> NetworkRequest {
            guard !url.isEmpty else { throw BuilderError.missingURL }
            return NetworkRequest(
                url: url, method: method, headers: headers,
                body: body, timeout: timeout
            )
        }
    }
}

Result Builders — Swift 5.4 introduziu @resultBuilder — um mecanismo de linguagem para construção declarativa de estruturas. SwiftUI, AttributedString, SceneBuilder usam result builders. É uma alternativa ao Builder clássico: em vez de uma cadeia de set-métodos, result builder usa um bloco de código com elementos que o compilador monta em um array ou árvore. @ViewBuilder no SwiftUI é o exemplo mais famoso: dentro de body você pode escrever if, switch, ForEach, e o compilador constrói uma View a partir das condições.

Builder vs Telescoping Constructor: comparação de abordagens

Telescoping Constructor — um antipadrão onde uma classe tem múltiplos construtores sobrecarregados com diferentes conjuntos de parâmetros. Por exemplo, três construtores: HttpConfig(url), HttpConfig(url, timeout), HttpConfig(url, timeout, retries). À medida que os parâmetros crescem, o número de construtores cresce exponencialmente — para n campos opcionais são necessárias n! combinações. Builder resolve este problema permitindo especificar apenas os campos necessários.

CaracterísticaTelescoping ConstructorBuilderKotlin named args
Quantidade de códigoCrescimento exponencialCrescimento linearMínimo
LegibilidadeBaixa (qual parâmetro é qual?)Alta (método + nome)Alta (nome = valor)
ImutabilidadeImutávelImutávelImutável
Compatibilidade JavaCompletaCompletaNenhuma (só Kotlin)
ValidaçãoEm cada construtorEm build() — uma vezEm init()

Kotlin named arguments + valores padrão — uma alternativa elegante ao Builder em projetos puramente Kotlin. Os parâmetros do construtor têm valores padrão, o cliente passa apenas os necessários: HttpConfig(baseUrl = url, timeout = 15_000). A desvantagem é a incapacidade de validar campos obrigatórios em tempo de compilação. Builder fornece campos obrigatórios através do construtor Builder (baseUrl é obrigatório). Para bibliotecas Java, Builder continua sendo o padrão de fato.

Builder no Android SDK: AlertDialog, Retrofit, OkHttp

Builder no Android SDK — um dos padrões mais comuns na biblioteca padrão. AlertDialog.Builder: new AlertDialog.Builder(context).setTitle().setMessage().setPositiveButton().create(). Retrofit.Builder: new Retrofit.Builder().baseUrl().addConverterFactory().build(). OkHttpClient.Builder: new OkHttpClient.Builder().connectTimeout().addInterceptor().build(). NotificationCompat.Builder: setContentTitle().setContentText().setSmallIcon().build().

Por que o Google usa Builder — compatibilidade retroativa. Adicionar um novo método ao Builder não quebra o código existente. Se o Google usasse um construtor com 20 parâmetros, cada novo campo exigiria uma nova sobrecarga. Builder permite adicionar set-métodos por anos sem breaking changes. Por exemplo, NotificationCompat.Builder adicionou setBubbleMetadata() no Android 11 sem afetar o código existente.

Builder em bibliotecas Kotlin — Ktor (HttpClientBuilder), Coil (ImageRequest.Builder), Room (Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build()), Navigation (NavOptionsBuilder). Em projetos Kotlin, Builder é frequentemente combinado com DSL: Room.databaseBuilder(context, AppDatabase.class, "db").fallbackToDestructiveMigration().build(). O padrão permanece relevante para APIs públicas onde a compatibilidade retroativa e a interoperabilidade Java são importantes.

Perguntas frequentes

Quando Builder é excessivo?

Builder é excessivo para objetos com 1-3 campos — um construtor comum ou data class é mais claro. Também é excessivo em projetos Kotlin sem interoperação Java, onde named arguments + valores padrão resolvem a mesma tarefa de forma mais simples. Builder é justificado para 5+ campos, validação complexa ou APIs Java onde named arguments não estão disponíveis.

Como Builder difere de Factory?

Builder cria um objeto complexo passo a passo (configuração de campos), Factory cria um objeto inteiro por tipo ou parâmetros. Builder responde à pergunta «como montar?», Factory responde «o que criar?». Builder é frequentemente combinado com Factory: Factory seleciona o tipo, Builder configura os campos.

Builder é necessário no SwiftUI?

No SwiftUI, o papel do Builder é desempenhado por result builders (@ViewBuilder, @SceneBuilder) e modificadores de View (.font(), .padding()). O Builder clássico não é necessário porque o SwiftUI usa uma abordagem declarativa e modificadores fluidos. Para componentes UIKit, Builder é útil: UIAlertController, URLRequest, NSAttributedString.

Como tornar Builder thread-safe?

Builder normalmente não requer segurança de thread já que é usado em uma única thread para montar um objeto. Se Builder for usado em um ambiente multithread (caso raro), sincronize cada set-método e build(). Alternativa — Immutable Builder: cada set-método retorna uma nova instância de Builder com o campo modificado.

Por que o Retrofit usa Builder em vez de DI?

Retrofit.Builder é uma API pública de biblioteca que deve funcionar sem um contêiner DI. Builder fornece flexibilidade de configuração (baseUrl, conversores, interceptadores, adaptadores de chamada personalizados) sem dependências de Dagger ou outros DI. Dentro de uma aplicação, DI pode criar Retrofit uma vez através do Builder, mas o Builder em si continua sendo parte da API pública do Retrofit.

Resumo

  • Builder — construção passo a passo de objetos com interface fluida
  • Kotlin Builder — clássico (classe aninhada) e DSL (lambda com receptor)
  • Swift Builder — classe aninhada ou @resultBuilder para código declarativo
  • Imutabilidade — Builder cria objetos imutáveis através de construtor privado
  • Android SDK — AlertDialog, Retrofit, OkHttp, NotificationCompat — padrão da indústria
  • Compatibilidade retroativa — adicionar campos ao Builder não quebra código existente
  • Alternativa Kotlin — named arguments + valores padrão mais simples para projetos puramente Kotlin

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também