π§© Builder Pattern
β Intentβ
- Construct complex objects step-by-step
- Use the same construction process to create different representations
β Motivationβ
- Helps manage initialization when there are many property combinations
- Allows for controlled construction with optional parameters, ordering, and validation
β When to Useβ
- When initializing objects with many options, such as forms or configuration objects
β Code Exampleβ
- TypeScript
- PHP
- Python
class Logger {
log(message: string): void {
console.log(`[LOG]: ${message}`);
}
}
// 対豑γ―γ©γΉ
class UserService {
constructor(private logger: Logger) {}
createUser(name: string) {
this.logger.log(`γ¦γΌγΆγΌδ½ζ: ${name}`);
}
}
// Builder
class UserServiceBuilder {
private logger: Logger | null = null;
setLogger(logger: Logger): this {
this.logger = logger;
return this;
}
build(): UserService {
if (!this.logger) {
throw new Error("Logger is required");
}
return new UserService(this.logger);
}
}
// ε©η¨δΎ
const builder = new UserServiceBuilder();
const service = builder.setLogger(new Logger()).build();
service.createUser("Hiroshi");
<?php
class Logger {
public function log(string $message): void {
echo "[LOG]: {$message}\n";
}
}
class UserService {
public function __construct(private Logger $logger) {}
public function createUser(string $name): void {
$this->logger->log("γ¦γΌγΆγΌδ½ζ: {$name}");
}
}
class UserServiceBuilder {
private ?Logger $logger = null;
public function setLogger(Logger $logger): self {
$this->logger = $logger;
return $this;
}
public function build(): UserService {
if (!$this->logger) {
throw new Exception("Logger is required");
}
return new UserService($this->logger);
}
}
// ε©η¨δΎ
$builder = new UserServiceBuilder();
$service = $builder->setLogger(new Logger())->build();
$service->createUser("Hiroshi");
class Logger:
def log(self, message: str):
print(f"[LOG]: {message}")
class UserService:
def __init__(self, logger: Logger):
self.logger = logger
def create_user(self, name: str):
self.logger.log(f"γ¦γΌγΆγΌδ½ζ: {name}")
class UserServiceBuilder:
def __init__(self):
self._logger: Logger | None = None
def set_logger(self, logger: Logger) -> "UserServiceBuilder":
self._logger = logger
return self
def build(self) -> UserService:
if not self._logger:
raise ValueError("Logger is required")
return UserService(self._logger)
# ε©η¨δΎ
builder = UserServiceBuilder()
service = builder.set_logger(Logger()).build()
service.create_user("Hiroshi")
β Explanationβ
This code applies the Builder
pattern to construct a complex object (UserService
) in a step-by-step manner.
The Builder
pattern separates the construction process, enabling flexible and safe object creation.
1. Overview of the Builder Patternβ
-
Builder: Defines the steps required to construct the object
- Represented by
UserServiceBuilder
in this code
- Represented by
-
Product: The object being constructed
- Represented by
UserService
- Represented by
-
Client: Uses the builder to construct the object
- In this code, the part that uses
UserServiceBuilder
to create aUserService
instance
- In this code, the part that uses
2. Key Classes and Their Rolesβ
-
Logger
- Utility class for logging
- Used as a dependency of
UserService
-
UserService
- The target class (Product)
- Provides user creation functionality and uses
Logger
to output logs
-
UserServiceBuilder
- The builder class
- Uses
setLogger
to set a logger, andbuild
to create aUserService
- Throws an error if required dependencies (e.g.,
Logger
) are not provided
-
Client Code
- Uses
UserServiceBuilder
to constructUserService
- Sets the required dependencies and calls
build
to create the instance
- Uses
3. UML Class Diagramβ
4. Benefits of the Builder Patternβ
- Flexibility: Dependencies can be set in stages
- Safety: Prevents incomplete objects by throwing errors when required dependencies are missing
- Readability: Method chaining provides a clear and intuitive construction process
This design enables safe and flexible construction of complex objects. It is especially useful when objects have many dependencies or require a detailed creation sequence.