점층적 생성자 패턴(Telescoping constructor pattern)
점층적 생성자 패턴(Telescoping constructor pattern)은 생정자(Constructor)의 호출 인자(Parameter)에 대해서 점층적으로 확장하며 오버로딩(Overloading) 정의하는 패턴입니다.
이 패턴은 다음과 같은 방식으로 구현됩니다.
- 필수 인자를 사용하는 생성자를 정의합니다.
- 필수 인자와 1개의 선택적인 인자를 사용하는 생성자를 정의합니다.
- 필수 인자와 2개의 선택적인 인자를 사용하는 생성자를 정의합니다.
- ...
- 모든 인자를 사용하는 생성자를 정의합니다.
/**
* 이 클래스는 사람에 대한 속성을 정의합니다.
* 점층적 생성자 패턴에 따라서 생성자를 정의합니다.
*/
public class People
{
public String name;
public String gender;
public int age;
/**
* 필수 인자를 사용하는 생성자를 정의합니다.
* 부족한 인자는 다음 오버로딩 생성자를 호출하면서 채워집니다.
*/
public People(String name)
{
this(name, "남성");
}
/**
* 필수 인자와 1개의 선택적인 인자를 사용하는 생성자를 정의합니다.
* 부족한 인자는 다음 오버로딩 생성자를 호출하면서 채워집니다.
*/
public People(String name, String gender)
{
this(name, gender, 1);
}
/**
* 모든 인자를 사용하는 생성자를 정의합니다.
*/
public People(String name, String gender, int age)
{
this.name = name;
this.gender = gender;
this.age = age;
}
}
점층적 생성자 패턴은 객체(Instance)를 생성하기 위한 인자를 선택적으로 생략 할 수 있다는 장점이 있습니다.
예를 들어, 남자 아이에 대한 출생 신고를 일괄 처리하는 함수의 경우 아래와 같이 작성 될 수 있습니다.
public People[] born(String ... names)
{
People[] people = new People[names.length];
int i = 0;
for (String name : names)
people[i++] = new People(name);
return people;
}
남자 아이가 출생하였을 때, gender="남성"이면서 age=1을 자동 기입합니다.
반면 생성자를 사용하기 위한 인자가 많아질수록 가독성이 떨어지는 단점이 있습니다.
다음 예시처럼 인자가 많아지면 각 인자가 어떤 의미로 사용되는지 한 눈에 파악되지 않습니다.
가독성이 떨어지면 생산성이 낮아지고 휴먼 에러의 가능성이 높아집니다.
new People("홍길동", "남성", 28, "031-9999-9999", "010-1234-5678", 43);
성능 좋은 컴파일러의 경우 인자의 변수명 등을 알려주기는 하지만, 이것만으로는 충분하지 않습니다.
자바빈 패턴(JavaBeans pattern)
점층적 생성자 패턴의 문제점을 보완하기 위한 방법으로 자바빈 패턴(JavaBeans pattern)을 사용 할 수 있습니다.
자바빈 패턴은 JSP의 자바빈(Java Bean)처럼 Setter 메소드를 구현하여 필드 값을 채워나가는 방식입니다.
Setter 메소드 명이 명확하게 네이밍되고 있다면, 각 인자의 의미를 파악하기 훨씬 수월해집니다.
또한 생성자를 인자 개수만큼 오버로딩하는 수고로움 역시 덜 수 있습니다.
People people = new People();
people.setName("홍길동");
people.setGender("남성");
people.setAge(28);
하지만 자바빈 패턴의 경우 객체 생성에 대한 일관성이 없다는 문제가 있습니다.
일관성이 없기 때문에 어떤 경우에는 Setter 메소드가 누락될 위험이 있습니다.
- 다른 코드에서 객체 생성을 하는 과정에서 누락
- 새로운 Setter 메소드가 추가될 때 기존 코드에서의 누락
그리고 Setter 메소드로 인해 불변(Immutable) 클래스를 만들 수 없다는 단점 또한 가지고 있습니다.
빌더 패턴(Builder pattern)
빌더 패턴에서는 점층적 생성자 패턴과 자바빈 패턴에서의 이슈를 해결하기 위한 목적으로 사용됩니다.
- 인자가 사용되는 의미가 불분명하여 가독성이 떨어지는 문제
- 객체 생성에 대한 일관성 문제
- 불변(Immutable) 클래스 생성이 가능한 형태 유지
빌더 패턴에서는 흔히 Builder라고 부르는 클래스를 정의합니다.
Builder 클래스에서는 패턴이 사용되려는 클래스에 대한 객체 생성을 직접적으로 관리하게 됩니다.
이 때 객체의 필수 인자는 Builder의 생성자에 의해서 전달되고, 선택적 인자는 Builder의 메소드 체이닝 패턴(Method chaining pattern)으로 구성하는 것이 일반적입니다.
/**
* 이 클래스는 사람에 대한 속성을 정의합니다.
* 빌더 패턴에 의해서 Builder 클래스를 추가 정의합니다.
*/
public class People
{
private String name;
private String gender;
private int age;
public People(People.Builder builder)
{
this.name = builder.name;
this.gender = builder.gender;
this.age = builder.age;
}
public static class Builder
{
// 필수 인자는 빌더에 의해서 파라미터를 요구합니다.
private String name;
// 선택적 인자는 default 값을 입력합니다.
private String gender = "남성";
private int age = 1;
public Builder(String name)
{
this.name = name;
}
public Builder gender(String gender)
{
this.gender = gender;
return this;
}
public Builder age(int age)
{
this.age = age;
return this;
}
}
}
빌더 패턴을 사용하면 다음과 같이 객체를 생성 할 수 있습니다.
객체가 Builder에 의해서 한 번에 생성되므로 일관성을 유지하기 좋고, 인자가 사용되는 의미가 명확하며 생성하려는 클래스가 Setter 메소드를 갖고있지 않으므로 불변 클래스로써 사용에도 적합합니다.
People people = new People(new People.Builder("홍길동")
.gender("남성")
.age(28));
'Java > Design patterns' 카테고리의 다른 글
상태 처리를 단순화하는 Flag 사용하기 (0) | 2023.11.24 |
---|---|
객체 생성 코드를 단순화 하는 메소드 체이닝 패턴(Method chaining pattern) (0) | 2023.08.29 |