[개발 일기] 2025.02.23 - @Builder를 사용하면 생성자가 private이라도 외부에서 접근 가능한 이유?

2025. 2. 23. 18:48·개발 일기

💡 개요

자바에서 많은 멤버변수를 가진 클래스 객체를 생성할 땐 가독성과 매개변수 파악을 위해 빌더 패턴을 자주 사용한다.

 

 

오늘은 이 빌더 패턴을 사용하는데, 생성자가 private 이라도 클래스 외부에서 접근 가능한 이유에 대해 정리해 보자.

 

 

 

📕 new() vs Builder

빌더 패턴이란 객체 생성과정에서 많은 매개변수를 입력해야 할 땐, 잘못된 매개변수를 입력할 가능성이 있다.

 

 

이런 상황을 대비하고, 객체 생성을 더 안전하게 하기 위해 만들어진 디자인 패턴이다.

 

 

 

🚀 new 메서드

 

다음은 많은 멤버 변수를 사용하는 Member 클래스와 생성자이다.

 

 

class Member {
    private Long id;
    private String name;
    private String nickname;
    private int age;
    private String phone;
    private String address;
    
    Member(Long id, String name, String nickname, int age, String phone, String address) {
        ...
    }
}

 

Member member = new Member(1L, "홍길동", "길동닉네임", 25, "010-1234-5678", "경상북도 구미시 ...");

 

 

Member 객체를 생성하는 코드를 보면 많은 매개변수가 들어가 있다.

 

 

만약 Member 객체를 생성하는 코드가 다음과 같이 변하면 어떻게 될까?

 

 

Member member = new Member(1L, "길동닉네임", "홍길동", 25, "010-1234-5678", "경상북도 구미시 ...");

 

 

코드를 보면 String name 과 String nickname 의 입력 매개변수 순서가 뒤바꿔져 있다.

 

 

비즈니스 적으로 잘못된 코드이다. 하지만 위의 문제는 컴파일러는 알아챌 수 없고, 개발자 입장에서도 눈치채기 힘들다.

 

 

이러한 문제점을 극복하기 위해 빌더 패턴을 사용한다.

 

 

 

🚀 Builder 패턴

 

다음은 Member 에 빌더 패턴을 직접 적용한 코드이다.

 

 

public class Member {
    private Long id;
    private String name;
    private String nickname;
    private int age;
    private String phone;
    private String address;

    private Member(MemberBuilder builder) {
        this.id = builder.id;
        this.name = builder.name;
        this.nickname = builder.nickname;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public static class MemberBuilder {
        private Long id;
        private String name;
        private String nickname;
        private int age;
        private String phone;
        private String address;

        public MemberBuilder id(Long id) {
            this.id = id;
            return this;
        }

        public MemberBuilder name(String name) {
            this.name = name;
            return this;
        }

        public MemberBuilder nickname(String nickname) {
            this.nickname = nickname;
            return this;
        }

        public MemberBuilder age(int age) {
            this.age = age;
            return this;
        }

        public MemberBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public MemberBuilder address(String address) {
            this.address = address;
            return this;
        }

        public Member build() {
            return new Member(this);
        }
    }

    public static MemberBuilder builder() {
        return new MemberBuilder();
    }
}

 

Member member = Member.builder()
         .id(1L)
         .name("홍길동")
         .nickname("길동짱짱맨")
         .age(25)
         .phone("010-1234-5678")
         .address("경북 구미시 ..")
         .build();

 

 

위 코드에서는 Builder를 활용하여 각 메서드를 통해 입력 파라미터를 설정하고, 메서드 체이닝 방식으로 함수를 실행하며 Member의 멤버 변수를 입력하고 있다.

 

 

이를 통해 잘못된 멤버 변수 설정을 조금이라도 더 안전하게 막을 수 있다.

 

 

 

Member.builder()

 

Member.builder() 메서드를 실행해 MemberBuilder 객체를 생성한다.

 

 

id(), name(), nickname(), …

 

MemberBuilder.id(), MemberBuilder.name(), MemberBuilder.nickname() 메서드를 실행하여 각 매개변수로 입력된 값을 MemberBuilder 멤버변수에 할당한다.

 

 

.build()

 

MemberBuilder.build() 메서드에 Member 생성자에 값이 할당된 MemberBuilder 를 매개변수로 입력한 후 실행한다.

 

 

 

🚀 @Builder

 

빌더 패턴의 장점은 확실하게 알겠다.

 

 

그런데 Member 클래스의 코드가 너무 지저분하다.

 

 

이러한 단점을 극복하기 위해 롬복에선 Builder를 알아서 생성해 주는 어노테이션을 지원한다.

 

 

public class Member {
    private Long id;
    private String name;
    private String nickname;
    private int age;
    private String phone;
    private String address;

    @Builder
    private Member(Long id, String name, String nickname, int age, String phone, String address) {
        this.id = id;
        this.name = name;
        this.nickname = nickname;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }
}

 

 

이런 식으로 생성자 위에 @Builder 어노테이션을 달면, 알아서 빌더 패턴과 관련된 코드를 모두 생성해 준다.

 

 

 

📕 @Builder를 사용하면 생성자가 private이라도 외부에서 접근 가능한 이유

자 오늘의 메인 컨텐츠다.

 

 

그런데 위에서 빌더 패턴을 설명하다 보니 이유를 자연스럽게 알게 되었다.

 

 

그 이유는 빌더 패턴에서 생성되는 빌더 클래스는 public static 형태로 정의되기 때문이다.

 

 

Builder 관련 메서드의 접근 제어자가 public 이고 정적(static)이므로, 해당 클래스 내부에서는 private 생성자에도 접근할 수 있다.

 

 

즉, 외부에서는 new 메서드를 호출해 직접 객체를 생성할 수 없지만, 같은 클래스 내부에 있는 빌더 클래스에서는 private 생성자를 호출할 수 있기 때문에 객체를 생성할 수 있는 것이다.

 

 

 

👨🏻‍💻 참고

https://projectlombok.org/api/lombok/Builder

'개발 일기' 카테고리의 다른 글

[개발 일기] 2025.02.25 - 전략 패턴  (0) 2025.02.25
[개발 일기] 2025.02.24 - == 연산자 vs Objects.isNull()  (0) 2025.02.24
[개발 일기] 2025.02.22 - JPA Entity 기본생성자  (0) 2025.02.22
[개발 일기] 2025.02.21 - CDN(콘텐츠 전송 네트워크)  (0) 2025.02.21
[개발 일기] 2025.02.20 - 리눅스 Swap Memory  (0) 2025.02.20
'개발 일기' 카테고리의 다른 글
  • [개발 일기] 2025.02.25 - 전략 패턴
  • [개발 일기] 2025.02.24 - == 연산자 vs Objects.isNull()
  • [개발 일기] 2025.02.22 - JPA Entity 기본생성자
  • [개발 일기] 2025.02.21 - CDN(콘텐츠 전송 네트워크)
오도형석
오도형석
  • 오도형석
    형석이의 성장일기
    오도형석
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • MSA 모니터링 서비스
        • DB
      • 스파르타 코딩클럽
        • SQL
        • Spring
      • 백엔드
        • Internet
        • Java
        • DB
      • 캡스톤
        • Django
        • 자연어처리
      • Spring
        • JPA
        • MSA
      • ETC
        • ERROR
      • 개발 일기 N
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 인기 글

  • 태그

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
오도형석
[개발 일기] 2025.02.23 - @Builder를 사용하면 생성자가 private이라도 외부에서 접근 가능한 이유?
상단으로

티스토리툴바