Builder
Publié le 23 Mai 2025Builder est un pattern de création très utile lorsqu’on veut construire un objet complexe étape par étape. Il est particulièrement utile quand un objet comporte beaucoup de paramètres pour sa création, s’il existe plusieurs façon de construire un objet ou si l’on veut éviter des “constructeurs à rallonge” (qui empile pleins de paramètres).
Principe
Exemples d’utilisations
Génération de formulaires HTML complexes de composants UI
Construction dynamique de requêtes SQL
Points d’attentions
(new UserBuilder())
->withName("John")
->witheEmail("john@email.com")
->withAvatar("avatar.jpg")
->build();
new User("John", "john@email.com", "avatar.jpg");
Implémenter un Builder
Voici un exemple en Go
package requestBuilder
import (
"bytes"
"errors"
"io"
"net/http"
"net/url"
)
type HttpRequestBuilder struct {
method string
baseURL string
headers map[string]string
queryParams map[string]string
body []byte
}
func NewHttpRequestBuilder() *HttpRequestBuilder {
return &HttpRequestBuilder{
headers: make(map[string]string),
queryParams: make(map[string]string),
}
}
func (b *HttpRequestBuilder) SetMethod(method string) *HttpRequestBuilder {
b.method = method
return b
}
func (b *HttpRequestBuilder) SetURL(url string) *HttpRequestBuilder {
b.baseURL = url
return b
}
func (b *HttpRequestBuilder) AddHeader(key, value string) *HttpRequestBuilder {
b.headers[key] = value
return b
}
func (b *HttpRequestBuilder) AddQueryParam(key, value string) *HttpRequestBuilder {
b.queryParams[key] = value
return b
}
func (b *HttpRequestBuilder) SetBody(body []byte) *HttpRequestBuilder {
b.body = body
return b
}
func (b *HttpRequestBuilder) Build() (*http.Request, error) {
if b.method == "" {
return nil, errors.New("HTTP method is required")
}
if b.baseURL == "" {
return nil, errors.New("URL is required")
}
// Construction de l'URL avec query params
u, err := url.Parse(b.baseURL)
if err != nil {
return nil, err
}
q := u.Query()
for k, v := range b.queryParams {
q.Set(k, v)
}
u.RawQuery = q.Encode()
// Corps de la requête
var bodyReader io.Reader
if b.body != nil {
bodyReader = bytes.NewBuffer(b.body)
}
req, err := http.NewRequest(b.method, u.String(), bodyReader)
if err != nil {
return nil, err
}
// Ajout des headers
for k, v := range b.headers {
req.Header.Set(k, v)
}
return req, nil
}
package main
import (
"fmt"
"training.go/builder/requestBuilder"
)
func main() {
builder := requestBuilder.NewHttpRequestBuilder().
SetMethod("POST").
SetURL("https://api.example.com/data").
AddHeader("Authorization", "Bearer token").
AddHeader("Content-Type", "application/json").
AddQueryParam("limit", "10").
SetBody([]byte(`{"name": "Toto"}`))
req, err := builder.Build()
if err != nil {
panic(err)
}
fmt.Println("Request built successfully:")
fmt.Println(req.Method, req.URL)
fmt.Println("Headers:", req.Header)
}
Le même exemple en PHP
namespace Practice\designPatterns\builder;
class HttpRequestBuilder
{
private string $method = 'GET';
private string $url = '';
private array $headers = [];
private array $queryParams = [];
private ?string $body = null;
public function withMethod(string $method): self
{
$this->method = strtoupper($method);
return $this;
}
public function withUrl(string $url): self
{
$this->url = $url;
return $this;
}
public function addHeader(string $key, string $value): self
{
$this->headers[$key] = $value;
return $this;
}
public function addQueryParam(string $key, string $value): self
{
$this->queryParams[$key] = $value;
return $this;
}
public function withBody(string $body): self
{
$this->body = $body;
return $this;
}
public function build(): array
{
if (empty($this->url)) {
throw new \InvalidArgumentException("URL is required");
}
$query = http_build_query($this->queryParams);
$fullUrl = $this->url . (!empty($query) ? '?' . $query : '');
return [
'method' => $this->method,
'url' => $fullUrl,
'headers' => $this->headers,
'body' => $this->body,
];
}
}
declare(strict_types=1);
use Practice\designPatterns\builder\HttpRequestBuilder;
require "./vendor/autoload.php";
$builder = new HttpRequestBuilder()
->withMethod('POST')
->withUrl('https://api.example.com/data')
->addHeader('Authorization', 'Bearer token')
->addHeader('Content-Type', 'application/json')
->addQueryParam('limit', '10')
->withBody(json_encode(['name' => 'Toto']));
$request = $builder->build();
// Simulons l'envoi
echo "Méthode : " . $request['method'] . PHP_EOL;
echo "URL : " . $request['url'] . PHP_EOL;
echo "Headers : " . print_r($request['headers'], true);
echo "Body : " . $request['body'] . PHP_EOL;