들어가기 전, 싱글톤 패턴을 복습해보자
2021.12.01 - [개발자가 될 때까지/JAVA] - [Java] 디자인패턴 - 싱글톤 패턴 (singleton pattern)
싱글톤 패턴은 단 하나의 인스턴스를 생성해 프로그램 전반에서 하나의 인스턴스만을 사용하게 하는 패턴이다.
다시 말하면, 프로그램 시작부터 종료 시까지 어떤 클래스의 인스턴스가 메모리 상에 단 하나만 존재할 수 있게 하고, 이 인스턴스에 대해 어디에서나 접근할 수 있도록 하는 패턴이다. (참고)
private 생성자를 만들고, private static 객체변수를 만들어 getInstance()로 접근할 수 있게 한다.
빌더 패턴(Builder pattern)이란?
빌더 패턴은 복잡한 객체를 생성하는 방법을 정의하는 클래스와 표현하는 방법을 정의하는 클래스를 별도로 분리하여, 서로 다른 표현이라도 이를 생성할 수 있는 동일한 절차를 제공하는 패턴입니다.
빌더 패턴은 생성해야 되는 객체가 Optional한 속성을 많이 가질 때 빛을 발휘합니다.
스터디를 하다보면 개념만 봐서는 이해가 안되는 경우가 많다.
왜 그리고 어떻게 클래스를 분리하는데? 라는 물음을 해결하기 위해 간단한 예제를 살펴보도록 하자.
빌더패턴을 사용해야하는 이유
public class Person {
private String name;
private int age;
private String hobby;
private String favoritAnimal;
public Person(String name, int age, String hobby, String favoritAnimal) {
this.name = name;
this.age = age;
this.hobby = hobby;
this.favoritAnimal = favoritAnimal;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getHobby() {
return hobby;
}
public String getFavoritAnimal() {
return favoritAnimal;
}
}
위와 같이 한 사람의 프로필을 담고있는 person클래스를 만들었다.
생성자를 통해 모든 매개변수를 받도록 하고있는데, 저들 중 hobby를 넣고 싶지 않다면 어떻게 해야할까?
객체를 생성할 때 다음과 같이 더미 데이터를 넣을 수 있지만 가독성이 떨어진다.
Person person = new Person("븨나네", 20, null, "cat");
그 대신 새로운 생성자를 추가하는 방법이 있다.
public Person(String name, int age, String favoritAnimal) {
this.name = name;
this.age = age;
this.favoritAnimal = favoritAnimal;
}
지금은 한가지 경우만 추가하면 되기 때문에 간단하게 해결되지만 데이터가 많은 곳에 새로운 정보를 추가하거나 빼거나 순서를 바꾸려고 하면 건드리기 까다로워질 것이다. 어우
이런 코드를 조금 더 명시적이고 명확하게 해주는 패턴이 바로 빌더 패턴(Builder pattern)이다
위 코드에 빌더 패턴을 적용해보자
빌더패턴 구현
public class Person {
private String name;
private int age;
private String hobby;
private String favoritAnimal;
private Person(PersonBuilder personBuilder) {
this.name = personBuilder.name;
this.age = personBuilder.age;
this.hobby = personBuilder.hobby;
this.favoritAnimal = personBuilder.favoritAnimal;
}
// 출력을 위해 toString 오버라이딩
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
", favoritAnimal='" + favoritAnimal + '\'' +
'}';
}
// 빌더 호출, 외부에서 접근할 수 있도록 static 메소드로 생성
public static PersonBuilder personBuilder() {
return new PersonBuilder();
}
// builder class
public static class PersonBuilder {
private String name;
private int age;
private String hobby;
private String favoritAnimal;
private PersonBuilder() {}
public PersonBuilder setName(String name) {
this.name = name;
return this;
}
public PersonBuilder setAge(int age) {
this.age = age;
return this;
}
public PersonBuilder setHobby(String hobby) {
this.hobby = hobby;
return this;
}
public PersonBuilder setFavoritAnimal(String favoritAnimal) {
this.favoritAnimal = favoritAnimal;
return this;
}
public Person build() {
return new Person(this);
}
}
}
한 사람의 정보를 저장하는 Person 클래스를 만들고 PersonBuilder 클래스를 만들었다.
Person 클래스는 private으로 생성자를 만들고, PersonBuilder를 static 메소드로 생성해주었다.
PersonBuilder 클래스는 setter메소드의 리턴 자료형을 PersonBuilder 객체로 지정해주어 메서드 체이닝을 가능하게 하였다.
빌더 패턴은 다음과 같이 사용할 수 있다.
Person person = Person.personBuilder()
.setName("븨나네")
.setAge(20)
.setHobby("뜨개질")
.setFavoritAnimal("고양이")
.build();
빌더 패턴을 적용하지 않았을 때보다 가독성이 좋고, 객체의 수정이 용이해진 걸 확인할 수 있다.
이렇게 빌더 패턴을 적용하면 다음과 같은 장점들을 얻을 수 있다.
- 필요한 데이터만 설정할 수 있음
- 유연성을 확보할 수 있음
- 가독성을 높일 수 있음
- 불변성을 확보할 수 있음
Person 클래스에는 setter메소드가 없고 생성자가 private으로 되어있으므로 외부에서 접근이 불가하다.
Lombok 라이브러리 - @Builder
위의 코드를 Lombok 라이브러리의 @Builder를 사용하면 위의 많은 코드들을 직접 짜지 않고 빌더 패턴을 적용할 수 있다.
// @Data 혹은 @Getter, @Setter 등등
@Builder
@AllArgsConstructor // 모든 인자를 가진 생성자 생성
@NoArgsConstructor // 인자가 없는 생성자 생성
public class Person {
private String name;
private int age;
private String hobby;
private String favoritAnimal;
}
참고
빌더 패턴(Builder Pattern)을 사용해야 하는 이유
빌더 패턴(Builder pattern) 이해 및 예제
'Study > JAVA' 카테고리의 다른 글
[JAVA] 날짜와 시간 API 정리 (0) | 2022.01.24 |
---|---|
[Java] 디자인패턴 - 싱글톤 패턴 (singleton pattern) (0) | 2021.12.01 |
[JAVA] String, StringBuffer, StringBuilder 차이 및 장단점 (0) | 2021.11.27 |
[Java] 람다식 (Lambda Expression) (0) | 2021.11.26 |
[Java] Stream API (0) | 2021.11.24 |