|
빌더 패턴(Builder Pattern)은 객체 생성 패턴 중 하나로, 복잡한 객체를 단계별로 생성할 수 있게 해줍니다. 이 패턴은 특히 많은 매개변수를 가진 생성자나 객체 생성 시 다양한 옵션을 제공해야 하는 경우에 유용합니다. 빌더 패턴을 사용하면 객체 생성의 유연성을 높이고, 가독성과 유지보수성을 향상시킬 수 있습니다.
빌더 패턴의 핵심 아이디어
1) 단계별 객체 생성: 빌더 패턴은 객체를 단계별로 생성할 수 있게 합니다. 각 단계에서 필요한 매개변수를 설정하고, 최종적으로 객체를 생성합니다.
2) 가독성 향상: 빌더 패턴을 사용하면 어떤 필드가 어떤 값으로 설정되는지 명확하게 볼 수 있습니다. 이는 많은 매개변수를 가진 객체를 생성할 때 특히 유용합니다.
3) 불변 객체: 빌더 패턴을 사용하면 객체 생성 후에는 상태를 변경할 수 없는 불변 객체를 쉽게 만들 수 있습니다.
빌더 패턴의 구성 요소
- Builder 클래스: 객체 생성을 담당하는 내부 클래스입니다. 이 클래스는 객체의 각 필드를 설정할 수 있는 메서드들을 제공하며, 최종적으로 객체를 생성하는 build() 메서드를 가집니다.
- Director 클래스 (선택적): 객체 생성 절차를 정의하는 클래스입니다. 빌더 패턴의 구현 시 반드시 필요한 것은 아니며, 주로 복잡한 객체 생성 절차를 캡슐화할 때 사용됩니다.
빌더 패턴의 예를 작성해 볼께요.
// Product 클래스: 생성될 객체
public class Product {
private final String name;
private final int price;
private final String description;
private Product(ProductBuilder builder) {
this.name = builder.name;
this.price = builder.price;
this.description = builder.description;
}
public static class ProductBuilder {
private String name;
private int price;
private String description;
public ProductBuilder setName(String name) {
this.name = name;
return this;
}
public ProductBuilder setPrice(int price) {
this.price = price;
return this;
}
public ProductBuilder setDescription(String description) {
this.description = description;
return this;
}
public Product build() {
return new Product(this);
}
}
@Override
public String toString() {
return "Product{name='" + name + "', price=" + price + ", description='" + description + "'}";
}
}
// Client 클래스: 빌더를 사용하는 클라이언트 코드
public class Client {
public static void main(String[] args) {
// setter를 이용해 입력
Product product = new Product.ProductBuilder()
.setName("Laptop")
.setPrice(1000)
.setDescription("High-end gaming laptop")
.build();
System.out.println(product);
}
}
위 소스에서 Product 클래스는 빌더 패턴을 사용하여 객체를 생성합니다. ProductBuilder 내부 클래스를 사용하여 Product 객체의 각 필드를 설정하고, build() 메서드를 호출하여 최종 객체를 생성합니다.
잠깐~ Lombok을 사용하면 빌더 패턴을 더 간편하게 구현할 수 있습니다.
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Product {
private String name;
private int price;
private String description;
}
// Client 클래스: 빌더를 사용하는 클라이언트 코드
public class Client {
public static void main(String[] args) {
// 내부적으로 setter를 이용하지만 코드 작성시 멤버필드만 적어 준다.
Product product = Product.builder()
.name("mouse")
.price(5000)
.description("good")
.build();
System.out.println(product);
}
}
위의 예시에서 Lombok의 @Builder 애너테이션을 사용하여 빌더 패턴을 간편하게 구현하였습니다. Lombok이 자동으로 빌더 클래스를 생성해 주기 때문에, 별도의 빌더 클래스를 작성할 필요가 없습니다.
마무리 정리 : 빌더 패턴은 복잡한 객체 생성을 단계별로 진행할 수 있도록 도와주는 디자인 패턴입니다.
장점:
- 객체 생성 절차의 가독성을 높여줍니다.
- 불변 객체를 쉽게 생성할 수 있습니다.
- 코드의 유연성과 유지보수성을 향상시킵니다.
Lombok을 사용하면 @Builder 애너테이션을 통해 빌더 패턴을 쉽게 구현할 수 있습니다. 이 패턴은 특히 많은 매개변수를 가지는 객체 생성이나 다양한 옵션을 제공해야 하는 경우에 유용하며, 코드의 가독성과 유지보수성을 크게 향상시킵니다.
자 그러면 본론으로 들어갑니다. -----------------------------------------
Lombok의 @Builder는 빌더 패턴을 간편하게 구현할 수 있도록 도와주는 애너테이션입니다. 빌더 패턴은 객체 생성 시 여러 매개변수를 사용할 때 유용하게 사용할 수 있는 디자인 패턴입니다. Lombok의 @Builder는 복잡한 객체 생성 과정을 단순화하고, 가독성을 높이며, 불변 객체를 쉽게 만들 수 있게 합니다.
주요 기능과 역할
1. 객체 생성의 간편화: @Builder를 사용하면, 생성자의 매개변수 순서를 기억할 필요 없이, 명시적으로 각 필드를 설정할 수 있습니다. 이는 많은 매개변수를 가진 객체를 생성할 때 유용합니다.
2. 가독성 향상: 빌더 패턴을 사용하면 어떤 필드가 어떤 값으로 설정되는지 명확히 볼 수 있습니다. 이는 특히 코드 리뷰나 유지보수 시 유리합니다.
3. 불변 객체 생성: 빌더 패턴을 사용하면 객체가 생성된 후 변경되지 않도록 할 수 있습니다. 이는 객체의 상태를 안정적으로 유지할 수 있게 도와줍니다.
* 기본 사용법 관련 소스 샘플
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Person {
private String name;
private int age;
private String address;
}
// 객체 생성
public class Main {
public static void main(String[] args) {
Person person = Person.builder()
.name("공기밥")
.age(27)
.address("역삼동 123")
.build();
System.out.println(person);
}
}
위 소스에서 @Builder 애너테이션을 사용하여 Person 클래스를 빌더 패턴으로 생성할 수 있게 했습니다.
필드의 유효성 검증
@Builder와 함께 필드의 유효성을 검증하는 로직을 추가할 수도 있습니다. 이는 @Builder 애너테이션을 사용하는 생성자나 메서드에서 가능합니다.
import lombok.Builder;
import lombok.ToString;
@Builder
@ToString
public class Person {
private String name;
private int age;
private String address;
public Person(String name, int age, String address) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be null or empty");
}
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.name = name;
this.age = age;
this.address = address;
}
}
위 예시에서 생성자 내부에 필드 유효성 검증 로직을 추가하였습니다. @Builder 애너테이션을 사용하여 객체를 생성할 때도 이 검증 로직이 적용됩니다.
----설명 추가 ------------------------------------------------------------------------------------------------
@Builder
빌드 패턴을 사용하여 객체를 생성할 수 있으며 객체 생성 후 setter를 통한 접근을 제한 할수 있어서 불변형 객체를 만들 수 있습니다. https://projectlombok.org/features/Builder
@Builder : builder 패턴을 사용 할 수 있게 선언
클래스명.builder() 로 시작하여 값을 셋팅 후 build()를 호출하여 객체 생성
BuilderVO b = BuilderVO.builder()
.id("test")
.age(22)
.build();
@Builder(toBuilder = true)
builder 패턴으로 생성된 객체의 일부 값을 변경한 새로운 객체를 생성
BuilderVO b = BuilderVO.builder()
.id("test")
.age(22)
.build();
// id/age 값만 변경된 새로운 객체를 생성
BuilderVO b2 = b.toBuilder().id("test2").age(22).build();
--------------------------------------------------------------------------------------------------------------------
마무리 정리
Lombok의 @Builder는 빌더 패턴을 손쉽게 적용할 수 있도록 도와주며, 객체 생성의 간편화, 가독성 향상, 불변 객체 생성 등의 장점을 제공합니다. 이를 통해 복잡한 객체 생성 과정을 단순화하고, 코드의 유지보수성을 높일 수 있습니다.