클래스를 만들 때 가장 기본이 되는 건 생성자는 만드는 일일 것이다.
생성자로 객체를 만들어 전달하는 건 컴퓨터 자료관리의 기본이다.
여기 영양소를 관리하는 클래스를 만든다고 가정해보자
public class NutritionFacts {
private int calories;
private int fat;
private int sodium;
private int carbohydrate;
.
.
.
}
이런 식으로 만들게 될 것이다.
가장 기본적인 방법은
그냥 생성자를 만드는 일이다.
public NutritionFacts(int calories, int fat, int sodium, int carbohydrate) {
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
이런 식으로
하지만 칼로리가 0인 음식도 있고(곤약) 다이어트 식품으로 관리된 지방 프리 제품도 있을 것이다.
그 때마다 생성자를 다시 만들어야한다.
지금은 4가지라 15가지의 경우의 수가 나오지만
영양소는 이 외에도 산, 마그네슘, 아연 등 그 종류가 어마어마하게 많다
이 모든 내용을 생성자로 생성하다 보면 코드 길이는 물론 효율도 좋지 않을 것이다.
그래서 고려해볼만 한 패턴은
setter를 이용하는 방법이다.
public class NutrtionFacts {
private int calories=0;
private int fat=0;
private int sodium=0;
private int carbohydrate=0;
public void setCalories(int calories) {
this.calories = calories;
}
public void setFat(int fat) {
this.fat = fat;
}
public void setSodium(int sodium) {
this.sodium = sodium;
}
public void setCarbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
}
}
기본생성자만 이용하면서
각 변수의 setter를 만들어 사용하는 것이다.
이런 방식으로 사용하면
public class Main {
public static void Main(String[] args) {
NutrtionFacts cocaCola = new NutrtionFacts();
cocaCola.setCalories(100);
cocaCola.setCarbohydrate(100);
cocaCola.setFat(100);
cocaCola.setSodium(100);
}
}
이런 형식으로 영양소를 setter로 설정할 수 있고
값이 필요할 땐 getter로 불러와서 사용하면 된다.
하지만 이런 방식에는 단점이 있다.
객체생성이 한번에 끝나지 않아서, 객체 일관성이 깨질 수가 있다.
저 코드에서 코카콜라 탄수화물 100 까지만설정했는데 프로그램이 갑자기 비정상적으로 종료됬다던가
누가 컴퓨터 코드를 뽑았다던가 하면
코카콜라 객체는 지방과 염분의 영양소가 설정되지 않은 상태가 되버린다.
버그의 원인도 될 수 있다.
이러한 단점을 해결하기 위한 Builder 패턴이 있다.
public class NutrtionFacts {
private final int servingSize; // 일일 섭취량 (mL)
private final int servings; // 섭취 빈도 (per container)
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 carbohydrate = 0;
private int sodium = 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 carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; }
public NutrtionFacts build(){
return new NutrtionFacts(this);
}
}
private NutrtionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
영양소 클래스 밑에 builder 클래스가 있다.
nutrition 을 외부에서 부를 때
생성자 builder를 부른다. builder로 먼저 필수적으로 들어갈 변수를 설정해주고(servingSize, serving) 자기자신을 리턴해주면서
다른 필요한 영양소도 설정해준다. 그다음 build 메소드를 불러 NutritionFacts의 매개변수로 자기자신을 넣는다
이렇게 하면 NutritionFacts의 생성자가 Builder를 받아 객체를 만들고, 이렇게 만들어진 객체가 호출된 쪽에 반환되는 형식이다.
public class Main {
public static void Main(String[] args) {
NutrtionFacts cocaCola = new NutrtionFacts.
Builder(240, 8).calories(100).carbohydrate(100).
fat(100).build();
}
}
이런식으로 사용이 가능하다.
이 패턴을 사용하면 이전 방법에서의 단점을 해결할 수 있다.
'프로그래밍 > Java' 카테고리의 다른 글
이펙티브 자바 규칙 4 - 객체 생성은 private 생성자로 막자 (0) | 2018.01.27 |
---|---|
이펙티브 자바 규칙 3 - 싱글톤 (0) | 2018.01.27 |
이펙티브 자바 규칙 1 - 정적 팩토리 메소드 (0) | 2018.01.23 |