[객체 생성 패턴] Chapter 4-3. Builder Pattern : 심플 빌더

 

✍️ 빌더 패턴, 심플 빌더 패턴

본 포스팅에서 소개할 빌더는 심플 빌더 패턴으로 이전 포스팅에서 다룬 빌더-디렉터 패턴과 구현 방식이 사뭇 다르다.

 

빌더-디렉터 패턴은 객체를 생성하는 과정이 인터페이스로 추상화됐다면

심플 빌더 패턴의 빌더는 static inner class(이하 정적 내부 클래스)로 정의된다. 

 

먼저 심플 빌더 패턴을 알아보기 전에 정적 내부 클래스에 대해 알아볼 필요가 있다.

 

🍊 정적 내부 클래스

정적 내부 클래스몇 가지 특징을 가지고 있다.

 

첫 번째, 이름에서 알 수 있듯 클래스의 내부에 정의된 클래스다.

public class OuterClass {
    public static class InnerStaticClass {
    }
}

 

두 번째, 외부 클래스의 인스턴스 없이 인스턴스 생성이 가능하다.

public class App {
    public static void main(String[] args) {
        OuterClass.InnerStaticClass innerStaticClass = new OuterClass.InnerStaticClass();
    }
}

public class OuterClass {
    public static class InnerStaticClass {
    }
}

 

세 번째, 외부 클래스의 static 멤버 변수와 static 메서드만 접근이 가능하다. 또한 외부 클래스의 private 멤버 변수와 private 메서드에 접근 가능하다.

public class OuterClass {
    private int nonStaticInt = 10;
    private static int staticInt = 20;

    private void nonStaticMethod(){}
    private static void staticMethod(){}

    public static class InnerStaticClass {
        private int value;

        public void foo(){
            value = nonStaticInt; // 불가능!!!
            nonStaticMethod(); // 불가능!!!

            value = staticInt; // 가능!!!
            staticMethod(); // 가능!!!
        }
    }
}

 

심플 빌더 패턴 코드와 정적 내부 클래스

빌더 패턴을 적용할 Student 클래스는 멤버 변수로 id(학번), name(이름), grade(학년), phoneNumber(전화번호)를 갖고 동시에 내부에 정적 클래스 StudentBuilder를 갖는다.

 

Student 클래스의 특이점으로 private 생성자를 갖는데, 외부로부터 객체 생성을 막고 내부 클래스인 StudentBuilder에서만 객체 생성을 허용하기 위함이다. 또 한 가지 눈여겨볼 건 Student의 id는 키값으로, 반드시 초기화가 필요한 멤버 변수이기에 StudentBuilder의 생성자에서 그 값을 받도록 강제했다.

 

심플 빌더 패턴 예제 코드

public class Student {
    private int id;

    private String name;
    private String grade;
    private String phoneNumber;

    private Student(StudentBuilder builder){
        this.id = builder.id;
        this.name = builder.name;
        this.grade = builder.grade;
        this.phoneNumber = builder.phoneNumber;
    }

    public static class StudentBuilder{
        private int id;

        private String name;
        private String grade;
        private String phoneNumber;

        public StudentBuilder(int id){
            this.id = id;
        }

        public StudentBuilder setName(String name){
            this.name =name;

            return this;
        }

        public StudentBuilder setGrade(String grade){
            this.grade =grade;

            return this;
        }

        public StudentBuilder setPhoneNumber(String phoneNumber){
            this.phoneNumber =phoneNumber;

            return this;
        }

        public Student getStudent(){
            return new Student(this);
        }
    }
}

 

빌더 패턴 사용 예제

public class App {
    public static void main(String[] args) {
        Student kangworld = new Student
                .StudentBuilder(1237)
                .setName("kangworld")
                .setPhoneNumber("010-1234-5678")
                .setGrade("sophomore")
                .getStudent();
    }
}

 

✏️ 심플 빌더 패턴, 내부 정적 클래스 정리

심플 빌더 패턴 정적 내부 클래스를 사용하는 이유를 정리해 보면

 

첫 번째, 내부 클래스(정적이든 아니든)는 외부 클래스의 private 멤버 변수와 private 메서드에 접근이 가능하다. 그렇다면, 빌더 패턴을 적용할 클래스의 생성자를 private으로 선언하고 내부 클래스를 정의하면 내부 클래스에서만 객체를 생성할 수 있게 된다.

이처럼 외부로부터 생성자를 숨기고 특정 클래스만이 객체를 생성하도록 제한하는 것은 빌더 패턴과 꽤나 잘 어울린다.

 

두 번째, 클래스 A가 '다른 하나의' 클래스 B만을 위해서 사용되는 클래스라면, 클래스 A를 클래스 B의 정적 내부 클래스로 정의하는 것이 두 클래스를 논리적으로 동시에 물리적으로 그룹핑하는 이점을 가진다.

빌더 클래스는 빌더 패턴을 적용할 클래스만을 위한 클래스이므로 빌더를 내부 정적 클래스로 정의하는 것은 매우 타당하다.

 

세 번째, 내부 정적 클래스는 외부 클래스의 인스턴스 없이도 인스턴스를 생성할 수 있다. 상상해 보라, 빌더 인스턴스를 생성하기 위해 빌더가 최종적으로 생성할 클래스의 인스턴스를 먼저 생성해야 한다면 얼마나 모순인가.

외부 클래스의 인스턴스 없이 빌더를 생성하고 빌더가 일련의 과정을 거쳐 외부 클래스의 인스턴스를 생성하는 것이 빌더 패턴이 가진 목적 그 자체이다.

 

 

 

  

 

인프런의 백기선님의 강의 코딩으로 학습하는 GoF의 디자인 패턴을 참고해서 작성했습니다.

 

코딩으로 학습하는 GoF의 디자인 패턴 - 인프런 | 강의

디자인 패턴을 알고 있다면 스프링 뿐 아니라 여러 다양한 기술 및 프로그래밍 언어도 보다 쉽게 학습할 수 있습니다. 또한, 보다 유연하고 재사용성이 뛰어난 객체 지향 소프트웨어를 개발할

www.inflearn.com