본문 바로가기

개발이야기/Effective Java

[Effective Java]생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.

규칙 2 생성자 인자가 많을 때는 Builder 패턴 적용을 고려하라.



Builder pattern은 객체에서 생성자에 들어갈 파라미터가 많든 적든 차례차례 파라미터를 받아들이고 모든 파라미터를 받은 뒤에 이 변수들을 통합해서 한번에 사용을 할 수 있다.


사진. 고도화된 빌더패턴



안드로이드에서도 이 패턴을 유용하게 많이 사용했는데, 이게 어떻게 이루어지고 사용을 했는지 몰랐다. AlertDialog가 그 예이다. 아래는 AlertDialog의 예시이다.


AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("종료 확인 대화 상자") .setMessage("앱을 종료 하시 겠습니까?").setCancelable(true)
.setPositiveButton("확인",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int whichButton) {
finish();
}
}
).setNegativeButton("취소",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int whichButton) {
dialog.cancel();
}
}
);
AlertDialog dialog = builder.create();
dialog.show();

안드로이드를 하다보면 이 패턴을 자주보게 된다. AlertDialog 뿐만아니라 Uri, Geofence 등등 해당 패턴을 많이 사용하고 있다는 것을 알 수 있었다.


기존에는 오버로딩(Overloading)을 활용하여 객체를 생성했으나 이는 어떤 파라미터를 받는지 쉽게 알 수 없고, 유지보수가 힘들 다는 단점이 있다. 그 사례는 아래에서 볼 수 있다.


public class Person {
private final string name;
private final string blood;
private final int age;
private final int hairColor;
public Person(string name, string blood) {
this(name, blood, 0, 0);
}
public Person(string name, string blood, int age) {
this(name, blood, age, 0);
}
public Person(string name, string blood, int hairColor) {
this(name, blood, 0, hairColor);
}
public Person(string name, string blood, int age, int hairColor) {
this.name = name;
this.blood = blood;
/..etc../
}
public static void main(String args[]) {
Person somin = new Person("somin","A");
Person wonYoung = new Person("won young","B",14); // what means 14?
Person hyunJun = new Person("hyun jun","C",12,124); // what means 12, 124?
}
}


이와 같이 12,14,124가 어떤 파라미터인지 알아보려면 해당 클래스에 대해서 알아야 하며 또한, 생성자의 파라미터 위치가 바뀌게 되면 이미 생성한 모든 생성자도 바꿀뿐더러, 추가, 수정도 매우 어렵게 됨을 알 수 있다. 이것을 간단하게 Builder pattern을 활용하면 유지보수를 편하게 만들고 가독성도 좋게 만들 수 있다. 자세한것은 아래의 코드를 보고 판단 가능하다.


public class Person {
private final string name;
private final string blood;
private final int age;
private final int hairColor;
public static class Builder {
private final string name;
private final string blood;
private int age;
private int hairColor;
public Builder(string name, string blood) {
//객체 생성에 반드시 받아야 하는 파라미터는 Builder에서 받음.
this.name = name;
this.blood = blood;
}
public Builder age(int age) {
this.age = age;
return this;
}
public Builder hairColor(int hairColor) {
this.hairColor = hairColor;
return this;
}
public Rects build() {
return new Person(this);
//마지막 build에서 완성.
}
}
public static void main(String args[]) {
//Person somin = new Person("somin","A");
//Person wonYoung = new Person("won young","B",14); // what means 14?
//Person hyunJun = new Person("hyun jun","C",12,124); // what means 12, 124?
//with builder pattern
Person somin = new Person("somin","A");
Person wonYoung = new Person("won young","B").age(14);
Person hyunJun = new Person("hyun jun","c").age(12).hairColor(124);
}
}


End of Document


반응형