빌더패턴이란...?
복잡한 객체의 생성과 그 표현을 분리하는 것이다. 그렇게 함으로써, 같은 생성자로 다른 표현을 만들 수 있다.
빌더패턴이 필요한 이유를 찾아보자.
먼저, 메서드 체인(method chaining)이라는 개념부터 알아야한다. 메서드가 객체를 반환하게 되면, 메서드의 반환 값인 객체를 통해 또 다른 함수를 호출하는 것을 말한다. 생성자에 return 특정 변수가 아닌, return this를 사용하여 클라스 인스턴스 변수를 모두 가져오는 방법이 있다.
final class Student{
private int id;
private String name;
//setter
public Student setId(int id)
{
this.id = id;
return this;
}
public Student setName(String name)
{
this.name = name;
return this;
}
@Override
public String toString()
{
return "id = " + this.id + ", name =" + this.name;
}
}
public class MethodChanin{
public static void main(String[] args){
Student s1 = new Student();
Student s2 = new Student();
s1.setId(1),setName("ram");
s2.setId(2).setName("shyam");
}
}
원래 setter를 쓸 때 ,
public void setName(String name)
{
this.name = name;
}
이런식으로 리턴타입을 void로 하였다. 하지만 return this값을 줘서 setName()을 한번 쓸 때마다 클라스 필드 변수를 모두 가져올 수 있게 하였다. 원래는 s1.setId(1)이렇게 한번만 쓸 수 있는데 return this로 클라스 변수 모두를 부르기 떄문에 s1.setId(1).setName("ram") 이렇게 쓸 수 있는 것이다.
메소드 체인은 이처럼 유용한 디자인 패턴일 수 있다. 하지만 하나의 변수 값을 동시에 불러내면 값이 안나오거나 에러가 나올 수 있다.
메서드 체인 에러나는 경우
final class Studnet{
private int id;
private String name;
private String address;
//setter
public Student setId(int id)
{
this.id = id;
return this;
}
public Student setName(String name)
{
this.name = name;
return name;
}
public Student setAddress(String address)
{
this.address = address;
return this;
}
@Override
public String toString()
{
return "id = " + this.id + ", name = " + this.name + ", address = " + this.address;
}
}
//client side code
class StudentReceiver{
private final Student student = new Student();
public StudentReceiver()
{
Thread t1 = new Thread(new Runnable(){
@Override
public void run()
{
student.setId(1).setName("ram").setAddress("Noida");
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run()
{
student.setId(2).setName("shyam").setAddress("delhi");
}
});
t1.start();
t2.start();
}
public Student getStudent()
{
return student;
}
}
//driver class
public class BuilderNeedDemo{
public static void main(String[] args){
studentReceiver sr = new StudentReceiver();
System.out.println(sr.getStuent());
}
}
위에서 run() 에 변수값을 주었는데 , 이때 thread 객체에 둘이 같이 들어가있고, 동시에 변수 값을 찾으려고 한다.
따라서 에러가 발생하거나 id = 2 name = null address = noida 이런식으로 불규칙으로 발생할 수 있다.
이러한 결과를 막기 위해 Builder 패턴을 사용한다.
빌더패턴 사용법:
// Server Side Code
final class Student {
// final instance fields
private final int id;
private final String name;
private final String address;
public Student(Builder builder)
{
this.id = builder.id;
this.name = builder.name;
this.address = builder.address;
}
// Static class Builder
public static class Builder {
/// instance fields
private int id;
private String name;
private String address;
public static Builder newInstance()
{
return new Builder();
}
private Builder() {}
// Setter methods
public Builder setId(int id)
{
this.id = id;
return this;
}
public Builder setName(String name)
{
this.name = name;
return this;
}
public Builder setAddress(String address)
{
this.address = address;
return this;
}
// build method to deal with outer class
// to return outer instance
public Student build()
{
return new Student(this);
}
}
@Override
public String toString()
{
return "id = " + this.id + ", name = " + this.name +
", address = " + this.address;
}
}
// Client Side Code
class StudentReceiver {
// volatile student instance to ensure visibility
// of shared reference to immutable objects
private volatile Student student;
public StudentReceiver()
{
Thread t1 = new Thread(new Runnable() {
@Override
public void run()
{
student = Student.Builder.newInstance()
.setId(1)
.setName("Ram")
.setAddress("Noida")
.build();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run()
{
student = Student.Builder.newInstance()
.setId(2)
.setName("Shyam")
.setAddress("Delhi")
.build();
}
});
t1.start();
t2.start();
}
public Student getStudent()
{
return student;
}
}
// Driver class
public class BuilderDemo {
public static void main(String args[])
{
StudentReceiver sr = new StudentReceiver();
System.out.println(sr.getStudent());
}
}
위에서 Builder.newInstance()를 하면 새로운 Builder객체를 만들어낸다.
public static Builder newInstance()
{
return new Builder();
}
'Java' 카테고리의 다른 글
SubString() 문자열 자르기 사용법 & 예제 정리 (0) | 2022.02.14 |
---|---|
call by value , 다른 객체로의 접근 (0) | 2022.01.30 |
this 키워드 모두 정리!! (변수,생성자,파라메터,클래스) (0) | 2022.01.15 |
인텔리제이에서 Javadoc 생성하기 (0) | 2022.01.13 |
오버라이딩 vs 오버로딩 (0) | 2022.01.08 |
댓글