🥕
TIL
  • [TIL] Studying tech / computer science knowledge
  • KeyMap
  • 알고리즘
    • 복잡도 계산 ( Computational Complexity )
    • DisjointSet-unionFind
    • Bellman-ford Algorithm
    • Dijkstra's Algorithm
    • DP ( Dynamic Programming , 동적 계획법 )
    • 플로이드-워셜 알고리즘 (Floyd-Warshall algorithm)
    • Kruskal's Algorithm
    • 최장 증가 수열 (Longes Increasing Subsequence)
    • Prim's Algorithm
    • 정렬
    • 시간복잡도 와 공간복잡도 ( Time Complexity & Space Complexity )
    • Topological Sort (위상 정렬)
  • 책 읽고난 후 요약
    • 프로그래밍 대회에서 배우는 알고리즘 문제해결 전략
    • cleancode
    • 도메인 주도 설계로 시작하는 마이크로서비스 개발
    • 오브젝트
  • CDC
    • debzium
    • kafka
  • 개발 상식
    • asciidoctor
    • 컴파일러
    • ELK 스택
    • 엔디안
    • git
    • Gitmoji
    • 테스트 종류
    • 라이브러리와 프레임워크
    • 정규 표현식
    • REST API
    • 동기와 비동기 / Blocking과 NonBlocking
    • Transaction Script와 Domain Model
    • 디자인 패턴
      • 행동 패턴
      • 객체 생성 패턴
        • 추상 팩토리 패턴
        • 빌더 패턴
        • 팩토리 메서드 패턴
        • [생성 패턴] 프로토 타입 (Prototype Parttern)
        • 싱글톤
      • 구조 패턴
        • 어댑터 패턴
        • 브릿지 패턴
        • 컴포짓(Composite) 패턴
        • 데코레이터
        • 프록시
    • refactoring
      • 중복 코드
      • 전역 데이터
      • 긴 함수
      • 긴 매개변수 목록
      • 가변 데이터
      • 이해하기 힘든 이름
  • 자료구조
    • AVL Tree
    • Splay Tree
    • aaTree
    • array-list
    • 자료구조 시간/공간 복잡도
    • 그래프
    • 힙
    • Red Black Tree
    • stack-queue
    • 트리 ( Tree )
  • DevOps
    • MSA
    • Kubernetes
      • AccessingAPI
      • controller
      • dashboard
      • kubernetes
      • object
      • pod
      • service
      • volume
  • Java
    • 어노테이션
    • 제어문
    • 데이터 타입
    • Enum
    • jvm
    • 연산자
    • thread
    • Java8
      • CompletableFuture
      • Date/Time
      • 어노테이션과 메타스페이스
      • 인터페이스
      • 람다식
      • Optional
      • 스트림
  • JavaScript
    • moduleProject
    • webpack-babel
    • 코어 자바스크립트
      • array
      • 함수 바인딩
      • 데코레이터와 포워딩
      • Class
      • 비교 연산자
      • Date 내장 객체
      • destructuring-assignment
      • function
      • 함수의 prototype 프로퍼티
      • 가비지 컬렉션 ( Garbage Collection )
      • JSON (JavaScript Object Notation)
      • map-set
      • 내장 프로토타입
      • new연산자와 생성자 함수
      • 객체
      • Object.keys, values, entries
      • 옵셔널 체이닝 '?.'
      • 프로퍼티 플래그
      • 프로퍼티 종류
      • 프로토 타입
      • 호출 스케줄링 ( scheduling a call )
      • scope
      • this
      • type-conversions
      • type
      • 함수의 자료형
      • var_let_const
  • Linux
    • 기본 명령어
    • 파일 종류
    • 리눅스
  • 네트워크
    • 응용 계층 ( Application Layer )
    • 오류 검출과 오류 정정
    • Http
    • Http Header
    • 컴퓨터 네트워크란
    • 네트워크 계층
    • 네트워크 제어 영역
    • 전송 계층 ( Transport Layer )
  • PHP
    • Facade
    • composer
    • scopeResolutionOperator
    • Laravel
      • SocialProvider
      • architecture
      • blade
      • controller
      • db
      • dbArchitecture
      • debug
      • eloquent
      • email
      • event
      • exceptionHandling
      • middleware
      • model
      • modelFactory
      • pagingLoading
      • queryBuilder
      • route
      • scout
      • seeding
      • tntsearch
      • validate
      • view
  • React
    • Next.js
    • React 란?
  • Spring
    • Controller
    • 요청이 들어왔을때 스프링이 처리하는 방법 ( 내부구조 )
    • ConfigurationProperties
    • Entity / DTO / VO
    • Maven
    • Repository와 DAO
    • 스프링 빈
    • Spring Framework
    • MVC 패턴
    • 도메인 입력값 검증
    • Spring Cloud
      • Spring Cloud
      • Eureka
    • Spring Data
      • JPA
      • JPA 어노테이션
      • 엔티티 비교
      • 복합 키와 식별 관계 매핑
      • JPA 예외처리
      • 객체지향 쿼리
      • EntityManagerFactory와 EntityManager
      • JPA 최적화
      • 프록시와 연관관계 맵핑
      • 연관관계
      • 상속관계 맵핑
      • 트랜잭션 범위와 영속성 컨텍스트
      • 데이터 타입
      • MySQL 연결
      • Pageable
    • Spring Project들과 library
      • Custom Serialize
      • Elasticsearch Index API
      • Spring HATEOAS
      • lombok (롬복)
      • Model Mapper
      • Object Mapper
      • Representation Model
      • Spring REST Docs
      • Spring Boot
    • Spring Security
      • Spring Security
      • Authentication
      • Authentication Filter
      • Authorization Filter
      • Filter Chain
      • SecurityContext
      • Spring OAuth2.0
    • Spring Test
      • AssertJ
      • Junit5
      • JunitParams
      • Mock Object
  • DataBase
    • ALIAS
    • CONCAT
    • CTE
    • Group By
    • HAVING
    • IFNULL
    • 인덱스
    • JOIN
    • ORDER BY
    • ROLLUP
    • SELECT
    • SELECT DISTINCT
    • SQL
    • WHERE
  • Web 상식
    • OAuth
    • WAS
    • HTTP통신 기반 인증
    • 브라우저
    • CSR 과 SSR
    • HTTPS
    • Web
Powered by GitBook
On this page
  • 객체 생성 방법
  • 1. 점층적 생성자 패턴
  • 2. 자바빈 패턴
  • 3. 빌더 패턴
  • Effective Java / Object의 Builder
  • 단점
  • @Builder
  • 팩토리패턴과 비교해보자
  • 사용 예시
  1. 개발 상식
  2. 디자인 패턴
  3. 객체 생성 패턴

빌더 패턴

객체의 생성과정과 표현 방법을 분리하여 동일한 생성 절차에서 다른 표현 결과를 만들 수 있게 하는 패턴.

객체 생성 방법

1. 점층적 생성자 패턴

class Person{
    private String firstName;
    private String lastName;
    private int age;
    private int height;
    private String hobby;

    Person() {}

    public Person(String firstName) {
        this.firstName = firstName;
    }

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

파라미터의 개수에 따른 서로다른 생성자가 필요할때 그때 그때 생성자를 추가하는 방법으로 가장 일반적인 패턴이다.

이는 특정 생성모양에 따라 계속 생성자를 추가해주어야되는 귀찮음이 존재한다.

public static void main(String[] args){
    //Constructor
    Person onlyFirstName = new Person("길동");
    Person onlyName = new Person("길동","홍");
    Person onlyLastName = new Person("홍"); //불가능

또한, 파라미터 갯수와 파라미터 타입이 동일한 생성자는 한개만 정의가 가능하기 때문에 위와같이 서로 다른 목적으로 사용하고 싶을때 사용할 수 없다.

2. 자바빈 패턴

class Person{
    private String firstName;
    private String lastName;
    private int age;
    private int height;
    private String hobby;

    public Person() {}
    public Person(String firstName, String lastName, int age, int height, String hobby) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.height = height;
        this.hobby = hobby;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}

//use
Person person = new Person();
person.setAge(25);
person.setHeight(180);
person.setHobby("음악");

위와 같은 클래스가 있을때 객체를 생성하는 과정에서 setter를 이용하여 객체를 정의하는 패턴

하지만 서비스가 멀티스레드 환경에 공유하는 객체가 필요하다라고 하면 객체가 변할수있는 상태라고 한다면 큰 문제가 될 수 있기 때문에 불변성을 만족해야 한다.

하지만 setter들로 인해 해당 객체는 언제든지 변경이 될 수 있는 상태이기때문에 클래스에서 setter는 외부에 열어두지 않는 것이 좋다.

3. 빌더 패턴

//Class
public class Person{
    String lastName;
    String firstName;

     public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

//Absract Builder
public abstract class PersonBuilder{
    protected Person person;

    public final void createPerson() {
        person = new Person();
    }

    public abstract void buildLastName();
    public abstract void buildFirstName();

    public Person getPerson(){
        return person;
    }
}

//Builder 
public class StandardPersonBuilder{
    public void buildLastName(){
        person.setLastName("홍");
    }
    public void buildFirstName(){
        person.setFirstName("길동");
    }
}

public class CustomPersonBuilder{
    public void buildLastName(){
        person.setLastName("김");
    }
    public void buildFirstName(){
        person.setFirstName("이박");
    }
}

//Director
public class Director {
    private Builder builder;

    public Director(Builder builder){
        this.builder = builder;
    }

    public void build() {
        builder.createPerson();
        builder.buildLastName();
        builder.buildFirstName();
    }

    public Person getPerson() {
        return builder.getPerson();
    }
}
public static void main(String[] args) {
    Builder personBuilder = new PersonBuilder();
    Director director = new Director(personBuilder);
    director.build();

    Person person = director.getPerson();
}

객체를 만들어 내는 Builder클래스를 이용하여 사용자는 지시자(Director)에게 특정 형태의 객체를 만들도록 요청할 수 있는 패턴으로 사용자는 서로다른 Builder를 Director에게 끼워주기만 하면 다른 형태의 객체를 만들어 낼 수있는 패턴.

여기서 중요한 건 동일한 생성 절차에서 다른 표현 결과를 만들 수 있다는 것이다.

물론 해당 구현 방식도 Person이라는 클래스가 setter가 열려있기 때문에 외부에서 언제든지 값을 변경이 가능하다.

Effective Java / Object의 Builder

class Person{
    private String firstName;
    private String lastName;

    public static Person.PersonBuilder builder() {
        return new Person.PersonBuilder();
    }

    public static class PersonBuilder{
        private String firstName;
        private String lastName;

        PersonBuilder() {
        }

        public Person.PersonBuilder firstName(final String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Person.PersonBuilder lastName(final String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Person build() {
            return new Person(this.firstName, this.lastName);
        }
    }
}

//use
Person person = new Pesron.builder()
    .firstName("길동")
    .lastName("홍")
    .build();

두 책에서의 말하고 있는 빌더 패턴은 생성자의 인자가 많을 경우 고려하라고 말하고 있으며 다음과 같은 문제를 해결할 수 있다.

  1. 불필요한 생성자를 제거

  2. 데이터의 순서에 상관없이 객체 생성

  3. 사용자입장에서 이해하기 쉬워야한다.

setter가 존재하지 않기 때문에 외부에서 값을 건드려 일관성이 깨지는 일이 존재하지 않으며 프로퍼티값을 검증하는 로직을 클래스에 두지 않고 객체를 생성해낼 수 있다.

단점

  1. 약간의 성능이슈 Builder를 생성하는 것도 하나의 객체를 생성하는 것이고 해당 객체가 다른 객체를 생성하는 것이기 때문에 약간의 메모리를 소비하게 된다.

  2. 코드의 유지보수 이는 대부분의 디자인패턴들의 공통적인 단점으로 관리하는 클래스들이 많아질 수 있으며 빌더를 inner 클래스에 정의해도 클래스가 길어져 가독성이 떨어질 수 있다. 또한 php와 같은 언어에서는 inner 클래스를 지원해주지 않기 때문에 사용이 불가능하다.

@Builder

Lombok 라이브러리의 @Builder 어노테이션을 사용하면 별도의 클래스 생성없이 컴파일러가 내부클래스로 Builder를 생성해준다.

class Person{
    private String firstName;
    private String lastName;
    private int age;
    private int height;
    private String hobby;

    public static Person.PersonBuilder builder() {
        return new Person.PersonBuilder();
    }

    public static class PersonBuilder{
        private String firstName;
        private String lastName;
        private int age;
        private int height;
        private String hobby;

        PersonBuilder() {
        }

        public Person.PersonBuilder firstName(final String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Person.PersonBuilder lastName(final String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Person.PersonBuilder age(final int age) {
            this.age = age;
            return this;
        }

        public Person.PersonBuilder height(final int height) {
            this.height = height;
            return this;
        }

        public Person.PersonBuilder hobby(final String hobby) {
            this.hobby = hobby;
            return this;
        }

        public Person build() {
            return new Person(this.firstName, this.lastName, this.age, this.height, this.hobby);
        }

        public String toString() {
            return "Person.PersonBuilder(firstName=" + this.firstName + ", lastName=" + this.lastName + ", age=" + this.age + ", height=" + this.height + ", hobby=" + this.hobby + ")";
        }
    }
}

다만 build()를 정의하면서 AllargumentsConstructor를 필요로 하기 때문에 원본클래스의 해당 생성자는 필수로 있어야 컴파일에러가 발생하지 않는다.

팩토리패턴과 비교해보자

  • 팩토리 메서드 패턴 : 객체를 생성하는 패턴에 있어 추상화를 적용할 수 있는 가작 간단한 패턴으로 단일 메서드를 사용하여 간단한 객체를 생성

    빌더패턴은 Director가 Builder를 제어하지만, 팩토리 메서드 패턴은 상위 클래스가 하위 클래스를 제어한다.

  • 추상 팩토리 패턴 : 복잡한 객체 생성을 담당한다는 점에서는 빌더 패턴과 유사하나 여러 팩토리 메서드를 사용하여 객체 생성하며 각 메서드들은 하위 객체를 바로 리턴한다.

  • 빌더 패턴 : 단계별로 복잡한 객체를 생성이 가능하며 각 중간단계에서의 상태를 유지하고 최종적으로 하위 객체들을 합친 최종 객체를 반환한다.

    한마디로 빌더패턴은 사용자가 최종결과물을 받고 추상 팩토리 패턴은 최종 결과물에 필요한 재료들을 받게 된다.

사용 예시

$partsFactory = new BioDataEngineerFactory($this->getRequest, $this->identity, $this->cookie);
$header = $partsFactory->createHeader();
$head = $partsFactory->createHead();
$body = $partsFactory->createBody();
$parameter = $partsFactory->createParameter();

$page = new Page($header,$head,$body,$parameter);
$page->assign();    
$partsBuilder = new BioDataEngineerBuilder($this->getRequest, $this->identity, $this->cookie);
$director = new Director(partsBuilder)
$director->createPage();

$page = $director->getPage();
$page->assign();    
Previous추상 팩토리 패턴Next팩토리 메서드 패턴

Last updated 3 years ago

abstractFactory-architecture
builder