관리 메뉴

Nirsa's Learning Lab

[Effective Java 3/E - 객체 생성과 파괴] Item 2. 생성자에 매개변수가 많다면 빌더를 고려하라 본문

Programming/JAVA

[Effective Java 3/E - 객체 생성과 파괴] Item 2. 생성자에 매개변수가 많다면 빌더를 고려하라

Nirsa 2025. 5. 30. 15:56
반응형

 

점층적 생성자 패턴과 자바 빈즈 패턴

점층적 생성자 패턴(Telescoping Consturctor Pattern)은 매개변수를 1개 받는 생성자, 2개 받는 생성자, 3개 받는 생성자와 같이 모든 매개 변수를 다 받는 생성자까지 늘려가는 형태로써 매개 변수가 들어오는 상황에 대한 모든 생성자가 만들어진 패턴입니다.

아래와 같이 모든 필드에 대해 매개 변수가 있는 생성자를 만들어 사용합니다.

public class Student {
    private String name;
    private int age;
    private String major;
    private String school;

    // 생성자1: 필수값만
    public Student(String name) {
        this(name, 0);
    }

    // 생성자2: 이름, 나이
    public Student(String name, int age) {
        this(name, age, null);
    }

    // 생성자3: 이름, 나이, 전공
    public Student(String name, int age, String major) {
        this(name, age, major, null);
    }

    // 생성자4: 이름, 나이, 전공, 학교
    public Student(String name, int age, String major, String school) {
        this.name = name;
        this.age = age;
        this.major = major;
        this.school = school;
    }
}

 

아래와 같이 인자 값의 순서를 바꿔 잘못 작성 하거나, 불필요한 값을 삽입해야하는 상황이 발생 할 수 있습니다.

public class Main {
	public static void main(String[] args) {
		// 인자 값을 잘못 전달한 경우
        	// Major와 school의 순서가 뒤바뀜
		Student s1 = new Student("Nirsa", 20, "티스토리 대학교", "컴퓨터 공학과");
		
		// 고등학생은 전공이 없기 때문에 빈 값 삽입
		Student s2 = new Student("Nirsa", 19, "", "티스토리 고등학교");
	}
}

 

또한, 만약 이러한 매개 변수가 4개가 아니라 8개, 16개, 32개가 넘어가면 걷잡을 수 없이 길어지고 복잡해 지며, 코드를 읽고 작성하는데 어려움이 생길 수 있습니다.

필요한 매개 변수만 선택하여 사용할 수 있도록 자바 빈즈 패턴(JavaBeans Pattern)이 있는데, 코드는 아래와 같습니다.

public class Main {
	public static void main(String[] args) {
		Student s = new Student();
		s.setName("Nirsa");
		s.setAge(20);
		s.setSchool("티스토리 대학교");
		s.setMajor("컴퓨터 공학과");
	}
}

class Student {
    private String name;
    private int age;
    private String school;
    private String major;

    public Student() { super(); }
    
    public void setName(String name) {
    	this.name = name;
    }
    
    public void setAge(int age) {
    	this.age = age;
    }
    
    public void setSchool(String school) {
    	this.school = school;
    }
    
    public void setMajor(String major) {
    	this.major = major;
    }
}

 

멤버 변수들에 대해 setter를 만들어 두고 필요한 곳에만 값을 저장할 수 있습니다.

하지만 이러한 자바 빈즈 패턴에서도 단점이 존재하는데, 객체를 완성시키기 위해 메서드(setter)를 여러 번 호출하고 필요한 값을 모두 넣고 객체를 완성시키기 전 까지는 일관성이 깨진 상태로 유지됩니다. 또한 setter로 데이터를 여러 번 입력을 받을 수 있으므로 불변으로 만들수도 없습니다.

 


 

빌더 패턴(Builder Pattern)

빌더 패턴은 객체 생성 시 어떤 값이 어떤 필드에 매핑되는지 한눈에 보이면서, 필요한 값만 선택적으로 설정이 가능하며, build() 메서드가 마지막으로 호출되며 불변 객체로 사용이 가능합니다.

아래의 코드는 필수값은 Builder 생성자에게 받으면서 선택 값은 메서드 체이닝으로 선택적으로 설정 합니다. 이러한 특성으로 필요한 값만 넣을 수 있으며 각 필드는 모두 final로 되어 있으므로 build() 후 불변 객체를 보장합니다.

public class Main {
	public static void main(String[] args) {
		// Student 객체를 Builder 패턴으로 생성
		Student s = new Student.Builder("Nirsa", 2)   // 필수값(name, age) 전달
					.school("티스토리 대학교") // 선택값(학교) 설정
					.major("컴퓨터 공학과")   // 선택값(전공) 설정
					.build();               // Student 객체 생성
	}
}

class Student {
	private final String name;   // 이름 (필수)
	private final int age;       // 나이 (필수)
	private final String major;  // 전공 (선택)
	private final String school; // 학교 (선택)
	
	// Student 객체 생성을 위한 Builder 내부 static 클래스
	public static class Builder {
		// 필수 매개변수
		private final String name;
		private final int age;
		
		// 선택 매개변수(기본값 세팅)
		private String major = "전공 없음";
		private String school = "학교 없음";
		
		// Builder 생성자 - 필수값만 초기화
		public Builder(String name, int age) {
			this.name = name;
			this.age = age;
		}
		
		// 전공 설정 (체이닝을 위해 Builder 반환)
		public Builder major(String value) {
			major = value;
			return this;
		}
		// 학교 설정 (체이닝을 위해 Builder 반환)
		public Builder school(String value) {
			school = value;
			return this;
		}
		
		// 최종적으로 Student 객체 생성
		public Student build() {
			return new Student(this);
		}
	}
	
	// Builder에서 값을 받아와서 Student 객체 생성 (private으로 외부 생성 차단)
	private Student(Builder builder) {
		name = builder.name;
		age = builder.age;
		major = builder.major;
		school = builder.school;
	}
}
반응형