public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public NutritionFacts (){}
...
...
..
public NutritionFacts (int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate){
this. 어쩌고 = 저쩌고;
this. 어쩌고 = 저쩌고;
...
...
..
}
위의 방법은 텔리스코핑 생성자 패턴 방식으로서 신축성이 좋지 않다....너무 당연한가?
.....생성할때 몇번째 인자가 뭔지 어떻게 아는가?-_-; 파라미터가 길어질수록 점점 더 난감해진다...또한 보면 알겠지만 가독성이 떨어진다.... 그러므로 나온게
자바빈즈 패턴....
이것은 다 알 것이다. 게터 세터 패턴~ 이클립스에서 자동으로 생성할 수 있는 간략한 패턴이다.
그러므로 코드는 생략!!
자바빈즈 패턴의 단점은 여러 번의 메소드 호출로 나누어져 인스턴스가 생성되므로 생성과정동안 객체가 일관된 상태를 유지 못할 수 있다. 그러므로 자바빈즈 패턴은 불변 클래스를 만들 수 있는 가능성을 배제하므로 스레드에서 안전성을 유지하려면 프로그래머의 추가적인 노력이 필요하다는 단점이 있다.
객체 생성이 완전히 끝났을 때 그 객체를 동결하고 완전하게 되기 전까지는 사용할 수 없도록 함으로써 단점을 줄일 수 있다. 그러나 이 방법은 매우 어렵다고 한다-_-;;;;(해볼 생각도 없었다...) 더욱이 런타임 에러를 유발할 수도 있다. 동결시키는 메소드를 객체 사용 전에 프로그래머가 호출 했는지 컴파일러가 확인할 수 없기 때문이다...
따라서 나온게 빌더 패턴이다.
빌더 패턴은 원하는 객체를 바로 생성하는 대신 클라이언트는 모든 필수 매개변수를 갖는 생성자를 호출하여 빌더 객체를 얻는다. 그 다음 빌더 객체의 세터 메소드를 호출하여 필요한 선택 매개변수들의 값을 설정한다. 그리고 클라이언트는 매개변수가 없는 build() 메소드를 호출하여 불변 객체를 생성하는 것이다. 말 그대로 불변 객체이므로 생성 후 상태 변화가 없다.
아래는 빌더패턴을 활용한 코드의 예 이다.
public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder {
private final int servingSize;
private final int servings;
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val) {
calories = val;
return this;
}
public Builder fat(int val) {
fat = val;
return this;
}
public Builder carbohydreate(int val) {
carbohydrate = val;
return this;
}
public Builder sodium(int val) {
sodium = val;
return this;
}
public NutritionFacts build() {
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public int getServingSize() {
return servingSize;
}
public int getServings() {
return servings;
}
public int getCalories() {
return calories;
}
public int getFat() {
return fat;
}
public int getSodium() {
return sodium;
}
public int getCarbohydrate() {
return carbohydrate;
}
}
빌더는 자신이 생성하는 객체의 클래스에 포함된 static 멤버 클래스이다. 위의 클래스는 불변 클래스이며, 모든 매개변수의 디폴트 값이 한군데 모아져 있다. 빌더의 세터 메소드들은 연속적으로 여러번 호출 될 수 있도록 빌더 자신의 객체를 반환한다.
NutritionFacts cocaCola=new NutritionFacts.Builder(240, 0).calories(100).sodium(35).carbohydreate(27).build();
이렇게 생성을 한다. 보면 쉽게 코드를 작성할 수 있고 가독성 또한 좋다. 생성자처럼 빌더는 자신의 매개변수에 불변 규칙을 적용할 수 있고 build 메소드는 그런 불변 규칙을 검사할 수 있다.
중요한 것은 매개변수들의 값이 빌더로부터 객체에 복사된 후 빌더의 필드가 아닌 객체의 필드에 대해 불변 규칙 검사가 수행되는 것이다. 만약 위배 될 경우에는 build 메소드에서 IllegalStateException 예외를 발생시킨다.
빌더 패턴은 유연성이 좋다. 하나의 빌더는 여러 개의 객체를 생성하는데 사용될 수 있으며 이런 과정 중 빌더 매개변수는 다양하게 조정될 수 있다. 빌더를 사용하면 일부 필드의 값을 자동으로 설정할 수 있다. 예를들어 하나의 객체가 생성될 때마다 자동적으로 증가하는 일련번호? ㄷㄷㄷ;
단점이라면 어떤 객체를 생성하기 위해서는 우선 그것의 빌더를 생성해야 한다는 것이다. 이는 빌더 객체의 생성 비용이 눈에 띄게 클 정도는 아니지만 성능이 매우 중요한 상황에서는 문제가 될 수도 있다.