Builder Pattern

최준호·2022년 11월 19일
0

Design Pattern

목록 보기
5/7
post-thumbnail

📗 Builder Pattern

빌더 패턴은 객체 인스턴스를 생성해주는 대표적인 패턴으로 spring에서 lombok을 사용했다면 디자인 구조를 몰라도 잘 사용해왔을 것이다.

그 패턴을 직접 구현하는 구조를 짜보자!

📄 패턴 적용 전

⌨️ 집 짓기!

public class House {
    private String elevator;
    private String window;
    private String park;
    private int room;
    private Boolean parking;

    public House() {
    }

    public House(String elevator, String window, String park, int room, Boolean parking) {
        this.elevator = elevator;
        this.window = window;
        this.park = park;
        this.room = room;
        this.parking = parking;
    }

    public void setElevator(String elevator) {
        this.elevator = elevator;
    }

    public void setWindow(String window) {
        this.window = window;
    }

    public void setPark(String park) {
        this.park = park;
    }

    public void setRoom(int room) {
        this.room = room;
    }

    public void setParking(Boolean parking) {
        this.parking = parking;
    }

    @Override
    public String toString() {
        return "House{" +
                "elevator='" + elevator + '\'' +
                ", window='" + window + '\'' +
                ", park='" + park + '\'' +
                ", room=" + room +
                ", parking=" + parking +
                '}';
    }
}

집을 짓기 위해 class를 정의했다. 해당 class를 통해 인스턴스를 생성하려면

public class Client {
    public static void main(String[] args) {
        House apartment = new House();
        apartment.setElevator("현대");
        apartment.setWindow("고급 창문");
        apartment.setPark("호수 공원");
        apartment.setParking(true);
        apartment.setRoom(500);

        House building = new House();
        building.setParking(false);
        building.setRoom(10);
        building.setWindow("일반 창문");

        System.out.println(apartment.toString());
        System.out.println(building.toString());
    }
}

다음과 같은 set 을 반복하는 코드를 작성하거나 길어진 생성자에 직접 매개변수를 일일히 넣어주어 생성해야한다.

이제 이를 builder 패턴을 적용시켜보자!

📄 패턴 적용 후

⌨️ Builder Interface 작성

public interface HouseBuilder {
    HouseBuilder elevator(String elevator);
    HouseBuilder window(String window);
    HouseBuilder park(String park);
    HouseBuilder room(int room);
    HouseBuilder parking(Boolean parking);
    House build();
}

기본 뼈대가 될 인터페이스를 작성했다. 여기서 주목할 점은 chaning을 위해 반환하는 객체 타입이 HouseBuilder를 반환하므로써 계속해서 체이닝이 가능하다는 것이다. 이 말이 이해가 안되면 좀있다 코드로 확인해보자.

⌨️ Builder 구현체 작성

public class DefaultHouseBuilder implements HouseBuilder{
    private String elevator;
    private String window;
    private String park;
    private int room;
    private Boolean parking;

    @Override
    public HouseBuilder elevator(String elevator) {
        this.elevator = elevator;
        return this;
    }

    @Override
    public HouseBuilder window(String window) {
        this.window = window;
        return this;
    }

    @Override
    public HouseBuilder park(String park) {
        this.park = park;
        return this;
    }

    @Override
    public HouseBuilder room(int room) {
        this.room = room;
        return this;
    }

    @Override
    public HouseBuilder parking(Boolean parking) {
        this.parking = parking;
        return this;
    }

    @Override
    public House build() {
        return new House(elevator, window, park, room, parking);
    }
}

⌨️ 집 짓기!

public class Client {
    public static void main(String[] args) {
        HouseBuilder apartBuilder = new DefaultHouseBuilder();
        House apartment = apartBuilder.elevator("현대")
                .window("고급 창문")
                .park("숲 공원")
                .room(500)
                .parking(true)
                .build();
                
        HouseBuilder buildingBuilder = new DefaultHouseBuilder();
        House building = buildingBuilder.window("일반 창문")
                .room(10)
                .parking(false)
                .build();

        System.out.println(apartment.toString());
        System.out.println(building.toString());
    }
}

위의 결과와 동일한 결과를 얻을 수 있는데. 위에서 set을 반복하던 코드에 비해 더 깔끔한 결과를 얻을 수 있었다.

여기서 builder pattern의 또 하나의 장점을 만들 수 있는데. 만약 아파트를 같은 구조로 계속 지어나간다면 계속 builder를 사용할 필요가 없이 지어진 그대로 가져오면 된다.

⌨️ apartment builder 정의해두기

public class ApartBuilder {
    private HouseBuilder houseBuilder;

    public ApartBuilder(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    public House prugio(){
        return houseBuilder
                .elevator("대우")
                .window("고급 창문")
                .room(500)
                .park("대우 공원")
                .parking(true)
                .build();
    }

    public House xi(){
        return houseBuilder
                .elevator("GS")
                .window("고급 창문")
                .room(500)
                .park("자이 공원")
                .parking(true)
                .build();
    }
}

다음과 같이 아파트 브랜드별로 찍어내고자 한다면

public class Client {
    public static void main(String[] args) {
        HouseBuilder builder = new DefaultHouseBuilder();
        ApartBuilder apartBuilder = new ApartBuilder(builder);
        House prugio = apartBuilder.prugio();
        House xi = apartBuilder.xi();

        System.out.println(prugio.toString());
        System.out.println(xi.toString());
    }
}

다음과 같은 결과도 확인해볼 수 있다.

📄 패턴의 장점과 단점

⌨️ 장점

복잡한 객체 생성 과정을 숨길 수 있고 더 세부적인 다양한 구조를 작성해볼 수 있다. 또한 지금은 build()에서 바로 new 객체()를 통해 반환하고 있지만 더 자세한 구현체를 얻기 위해 null 체크를 한다던지 들어올 수 없는 값을 체크한다던지 로직을 추가하여 더욱 단단한 객체를 반환해줄 수도 있다.

⌨️ 단점

단점으로는 builder라는 객체를 생성 해주어야하는 성능적인 부분이 존재하고, 다른 디자인 패턴들에서도 함께 존재하는 구조가 복잡해진다는 단점이 있다.

profile
코딩을 깔끔하게 하고 싶어하는 초보 개발자 (편하게 글을 쓰기위해 반말체를 사용하고 있습니다! 양해 부탁드려요!) 현재 KakaoVX 근무중입니다!

0개의 댓글