๐Ÿ“š ๋นŒ๋”(Builder)ํŒจํ„ด

CodeByHanยท2025๋…„ 4์›” 10์ผ

์Šคํ”„๋ง

๋ชฉ๋ก ๋ณด๊ธฐ
20/33

๋นŒ๋”(Builder)ํŒจํ„ด์ด๋ž€?

  • ๋ณต์žกํ•œ ๊ฐ์ฒด์˜ ์ƒ์„ฑ ๊ณผ์ •๊ณผ ํ‘œํ˜„ ๋ฐฉ๋ฒ•์„ ๋ถ„๋ฆฌํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๊ตฌ์„ฑ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ์ƒ์„ฑํŒจํ„ด์ด๋‹ค.
  • ์ƒ์„ฑ์ž์— ๋“ค์–ด๊ฐˆ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ํ•˜๋‚˜ํ•˜๋‚˜ ๋ฐ›์•„๋“ค์ด๊ณ  ๋งˆ์ง€๋ง‰์— ํ†ตํ•ฉ ๋นŒ๋“œํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธํ•œ๋‹ค.

โ—๏ธ ์˜ˆ๋ฅผ ๋“ค์–ด ์Šคํƒ€๋ฒ…์Šค ์Œ๋ฃŒ ์ฃผ๋ฌธ์„ ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์Šคํƒ€๋ฒ…์Šค์—์„œ ์Œ๋ฃŒ๋ฅผ ์ฃผ๋ฌธํ•  ๋•Œ ์ผ๋ฐ˜ ์•„๋ฉ”๋ฆฌ์นด๋…ธ ์ด์™ธ์—๋„ ์ƒท ์ถ”๊ฐ€, ์šฐ์œ  ์ข…๋ฅ˜ ๋ณ€๊ฒฝ, ์‹œ๋Ÿฝ ์ถ”๊ฐ€, ์–ผ์Œ ์–‘ ์กฐ์ ˆ ๋“ฑ ์‚ฌ๋žŒ๋งˆ๋‹ค ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋А ์‚ฌ๋žŒ์€ ์ƒท์„ ์ถ”๊ฐ€ํ•ด๋‹ฌ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๊ณ , ๋˜ ์–ด๋–ค ์‚ฌ๋žŒ์€ ์šฐ์œ ๋ฅผ ์˜คํŠธ๋ฐ€ํฌ๋กœ ๋ฐ”๊ฟ”๋‹ฌ๋ผ๊ณ  ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด์ฒ˜๋Ÿผ ์„ ํƒ์  ์˜ต์…˜๋“ค์„ ๋ณด๋‹ค ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ›์•„ ๋‹ค์–‘ํ•œ ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด, ํด๋ž˜์Šค์˜ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋นŒ๋” ํŒจํ„ด์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋นŒ๋”(Builder)ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ?

๋นŒ๋” ํŒจํ„ด ์ ์šฉ X ,์ƒ์„ฑ์ž ์˜ค๋ฒ„๋กœ๋”ฉ๋งŒ ์‚ฌ์šฉ

class Coffee {

    // ํ•„์ˆ˜ 
    private String type;   // ์˜ˆ: "์•„๋ฉ”๋ฆฌ์นด๋…ธ", "๋ผ๋–ผ" ๋“ฑ
    private int size;      // ์˜ˆ: 1 (Short), 2 (Tall), 3 (Grande)

    // ์„ ํƒ 
    private boolean extraShot;  // ์ƒท ์ถ”๊ฐ€ ์—ฌ๋ถ€
    private String milk;        // ์šฐ์œ  ์ข…๋ฅ˜ (์˜ˆ: "๊ธฐ๋ณธ์šฐ์œ ", "์˜คํŠธ๋ฐ€ํฌ", "๋‘์œ ")
    private boolean noIce;      // ์–ผ์Œ ์ œ์™ธ ์—ฌ๋ถ€
    private String syrup;       // ์‹œ๋Ÿฝ ์ข…๋ฅ˜ (์˜ˆ: "๋ฐ”๋‹๋ผ", "ํ—ค์ด์ฆ๋„›", "์—†์Œ")

    // ๋ชจ๋“  ์˜ต์…˜์„ ์ง€์ •ํ•˜๋Š” ์ƒ์„ฑ์ž
    public Coffee(String type, int size, boolean extraShot, String milk, boolean noIce, String syrup) {
        this.type = type;
        this.size = size;
        this.extraShot = extraShot;
        this.milk = milk;
        this.noIce = noIce;
        this.syrup = syrup;
    }

    // ์‹œ๋Ÿฝ ์˜ต์…˜ ์—†์ด (๊ธฐ๋ณธ๊ฐ’ "์—†์Œ"์œผ๋กœ ์„ค์ •)
    public Coffee(String type, int size, boolean extraShot, String milk, boolean noIce) {
        this(type, size, extraShot, milk, noIce, "์—†์Œ");
    }

    // ์–ผ์Œ ์˜ต์…˜ ์—†์ด (๊ธฐ๋ณธ noIce = false, ์‹œ๋Ÿฝ "์—†์Œ")
    public Coffee(String type, int size, boolean extraShot, String milk) {
        this(type, size, extraShot, milk, false, "์—†์Œ");
    }

    // ์šฐ์œ  ์˜ต์…˜ ์—†์ด (๊ธฐ๋ณธ milk = "๊ธฐ๋ณธ์šฐ์œ ", noIce = false, ์‹œ๋Ÿฝ "์—†์Œ")
    public Coffee(String type, int size, boolean extraShot) {
        this(type, size, extraShot, "๊ธฐ๋ณธ์šฐ์œ ", false, "์—†์Œ");
    }

    @Override
    public String toString() {
        return String.format("์ปคํ”ผ ํƒ€์ž…: %s, ์‚ฌ์ด์ฆˆ: %d, ์ƒท ์ถ”๊ฐ€: %s, ์šฐ์œ : %s, ์–ผ์Œ ์ œ์™ธ: %s, ์‹œ๋Ÿฝ: %s",
                type, size, extraShot ? "์˜ˆ" : "์•„๋‹ˆ์˜ค", milk, noIce ? "์˜ˆ" : "์•„๋‹ˆ์˜ค", syrup);
    }
    
    public static void main(String[] args) {
        // ๋ชจ๋“  ์˜ต์…˜์ด ์ง€์ •๋œ ์ปคํ”ผ ์ฃผ๋ฌธ
        Coffee coffee1 = new Coffee("์•„๋ฉ”๋ฆฌ์นด๋…ธ", 3, true, "์˜คํŠธ๋ฐ€ํฌ", true, "๋ฐ”๋‹๋ผ");

        // ์ƒท ์ถ”๊ฐ€๋งŒ ์ง€์ •ํ•œ ๊ธฐ๋ณธ ์ปคํ”ผ ์ฃผ๋ฌธ
        Coffee coffee2 = new Coffee("์•„๋ฉ”๋ฆฌ์นด๋…ธ", 2, true);

        // ์šฐ์œ  ๋ณ€๊ฒฝ๊ณผ ์–ผ์Œ ์ œ์™ธ ์˜ต์…˜๋งŒ ์ถ”๊ฐ€ํ•œ ์ปคํ”ผ ์ฃผ๋ฌธ
        Coffee coffee3 = new Coffee("๋ผ๋–ผ", 2, false, "๋‘์œ ", true);

        System.out.println(coffee1);
        System.out.println(coffee2);
        System.out.println(coffee3);
    }
}
  • ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ผ ๋•Œ, ์ƒ์„ฑ์ž ์˜ค๋ฒ„๋กœ๋”ฉ ๋ฐฉ์‹์€ ๊ฐ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ์ƒ์„ฑ์ž๋ฅผ ์ •์˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ๋‹ค.

๋นŒ๋”(Builder)ํŒจํ„ด ๋„์ž…

๋นŒ๋” ํŒจํ„ด์€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ Builder ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด step-by-step ์œผ๋กœ ๊ฐ’์„ ์ž…๋ ฅ๋ฐ›์€ ํ›„์— ์ตœ์ข…์ ์œผ๋กœ build() ๋ฉ”์†Œ๋“œ๋กœย ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฆฌํ„ดํ•˜๋Š” ํŒจํ„ด

 public static void main(String[] args) {
   // ์ƒ์„ฑ์ž ๋ฐฉ์‹
   Coffee coffee1 = new Coffee("์•„๋ฉ”๋ฆฌ์นด๋…ธ", 3, true, "์˜คํŠธ๋ฐ€ํฌ", true, "๋ฐ”๋‹๋ผ");

   // ๋นŒ๋” ๋ฐฉ์‹
   Coffee coffee2 = new Coffee.Builder("๋ผ๋–ผ", 2)
          .extraShot(true)
          .milk("๋‘์œ ")
          .noIce(true)
          .build();
    }
  • ๋ฐ์ดํ„ฐ์˜ ์ˆœ์„œ์— ์ƒ๊ด€์—†์ด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋‚ด ์ƒ์„ฑ์ž ์ธ์ž ์ˆœ์„œ๋ฅผ ํŒŒ์•…ํ•  ํ•„์š”๋„ ์—†๊ณ  ์ž˜๋ชป๋œ ๊ฐ’์„ ๋„ฃ๋Š” ์‹ค์ˆ˜๋„ ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค
public class Coffee {


    private String type;      // ์˜ˆ: "์•„๋ฉ”๋ฆฌ์นด๋…ธ", "๋ผ๋–ผ" ๋“ฑ
    private int size;         // ์˜ˆ: 1 (Short), 2 (Tall), 3 (Grande)
    private boolean extraShot;  // ์ƒท ์ถ”๊ฐ€ ์—ฌ๋ถ€
    private String milk;        // ์šฐ์œ  ์ข…๋ฅ˜ (์˜ˆ: "๊ธฐ๋ณธ์šฐ์œ ", "์˜คํŠธ๋ฐ€ํฌ", "๋‘์œ ")
    private boolean noIce;      // ์–ผ์Œ ์ œ์™ธ ์—ฌ๋ถ€
    private String syrup;       // ์‹œ๋Ÿฝ ์ข…๋ฅ˜ (์˜ˆ: "๋ฐ”๋‹๋ผ", "ํ—ค์ด์ฆ๋„›", "์—†์Œ")

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

    // private ์ƒ์„ฑ์ž (๋นŒ๋”๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๊ฐ์ฒด ์ƒ์„ฑ)
    private Coffee(Builder builder) {
        this.type = builder.type;
        this.size = builder.size;
        this.extraShot = builder.extraShot;
        this.milk = builder.milk;
        this.noIce = builder.noIce;
        this.syrup = builder.syrup;
    }

    // ๋‚ด๋ถ€ ๋นŒ๋” ํด๋ž˜์Šค
    public static class Builder {
        private String type;
        private int size;
        private boolean extraShot; 
        private String milk;
        private boolean noIce; 
        private String syrup;

        public Builder type(String type) {
            this.type = type;
            return this;
        }

        public Builder size(int size) {
            this.size = size;
            return this;
        }

        public Builder extraShot(boolean extraShot) {
            this.extraShot = extraShot;
            return this;
        }

        public Builder milk(String milk) {
            this.milk = milk;
            return this;
        }

        public Builder noIce(boolean noIce) {
            this.noIce = noIce;
            return this;
        }

        public Builder syrup(String syrup) {
            this.syrup = syrup;
            return this;
        }

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

   
    public String getType() {
        return type;
    }

    public int getSize() {
        return size;
    }

    public boolean isExtraShot() {
        return extraShot;
    }

    public String getMilk() {
        return milk;
    }

    public boolean isNoIce() {
        return noIce;
    }

    public String getSyrup() {
        return syrup;
    }

    @Override
    public String toString() {
        return String.format("์ปคํ”ผ [ํƒ€์ž…=%s, ์‚ฌ์ด์ฆˆ=%d, ์ƒท ์ถ”๊ฐ€=%s, ์šฐ์œ =%s, ์–ผ์Œ ์ œ์™ธ=%s, ์‹œ๋Ÿฝ=%s]",
                type, size, extraShot ? "์˜ˆ" : "์•„๋‹ˆ์˜ค", milk, noIce ? "์˜ˆ" : "์•„๋‹ˆ์˜ค", syrup);
    }
}
  public static void main(String[] args) {
  Coffee coffee1 = new Coffee("์•„๋ฉ”๋ฆฌ์นด๋…ธ", 3, true, "์˜คํŠธ๋ฐ€ํฌ", true, "๋ฐ”๋‹๋ผ"); 

   // ๋นŒ๋” ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“  ์ปคํ”ผ ๊ฐ์ฒด
   Coffee coffee2 = Coffee.builder()
                .type("๋ผ๋–ผ")
                .size(2)
                .extraShot(true)
                .milk("๋‘์œ ")
                .noIce(true)
                .syrup("ํ—ค์ด์ฆ๋„›")
                .build();
    }

@Builder

๋นŒ๋” ํŒจํ„ด์„ ์ˆ˜์ž‘์—…์œผ๋กœ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ์„ค์ •ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ ํ•„๋“œ์— ๋Œ€ํ•ด ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋งŒ๋“ค์–ด์ค˜์•ผํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ข€๋” ํŽธํ•˜๊ฒŒ ๋นŒ๋” ํŒจํ„ด์„ ์ด์šฉํ•˜๊ธฐ ์œ„ํ—ค Lombok์—์„œ๋Š” ๋ณ„๋„์˜ ์–ด๋…ธํ…Œ์ด์…˜์„ ์ง€์›ํ•œ๋‹ค.

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@ToString
public class Coffee {

    private String type;      // ์˜ˆ: "์•„๋ฉ”๋ฆฌ์นด๋…ธ", "๋ผ๋–ผ" ๋“ฑ
    private int size;         // ์˜ˆ: 1 (Short), 2 (Tall), 3 (Grande)
    private boolean extraShot;  // ์ƒท ์ถ”๊ฐ€ ์—ฌ๋ถ€
    private String milk;        // ์šฐ์œ  ์ข…๋ฅ˜ (์˜ˆ: "๊ธฐ๋ณธ์šฐ์œ ", "์˜คํŠธ๋ฐ€ํฌ", "๋‘์œ ")
    private boolean noIce;      // ์–ผ์Œ ์ œ์™ธ ์—ฌ๋ถ€
    private String syrup;       // ์‹œ๋Ÿฝ ์ข…๋ฅ˜ (์˜ˆ: "๋ฐ”๋‹๋ผ", "ํ—ค์ด์ฆ๋„›", "์—†์Œ")
}
public static void main(String[] args) {

        Coffee coffee2 = Coffee.builder()
                .type("๋ผ๋–ผ")
                .size(2)
                .extraShot(true)
                .milk("๋‘์œ ")
                .noIce(true)
                .syrup("ํ—ค์ด์ฆ๋„›")
                .build();
                
        System.out.println(coffee2);
    }
  • @AllArgsConstructor(access = AccessLevel.PRIVATE) : @Builder์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ๋  ๋•Œ ์ฃผ๋กœ ์„ ์–ธ๋˜๋ฉฐ, ์ „์ฒด ํ•„๋“œ๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค๋˜, ์ด๋ฅผ private ์ƒ์„ฑ์ž๋กœ ์ œํ•œํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์™ธ๋ถ€์—์„œ ์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๊ณ , Builder๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋„๋ก ์œ ๋„ํ•œ๋‹ค.

๐Ÿค” @NoArgsConstructor(access = AccessLevel.PROTECTED)๋Š” ๋นŒ๋” ํŒจํ„ด์— ๊ผญ ํ•„์š”ํ•œ ๊ฑด ์•„๋‹ˆ์ง€๋งŒ, JPA๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜๋‹ค.
ํ•˜์ง€๋งŒ ์•„๋ฌด๋‚˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋ฉด ์„ค๊ณ„์ƒ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ,
์ƒ์„ฑ์ž์˜ ์ ‘๊ทผ ๋ฒ”์œ„๋ฅผ protected๋กœ ์ œํ•œํ•ด ์™ธ๋ถ€์—์„œ๋Š” ์ง์ ‘ ์ƒ์„ฑํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๋Š”๋‹ค.

์ฐธ๊ณ  :

profile
๋…ธ๋ ฅ์€ ๋ฐฐ์‹ ํ•˜์ง€ ์•Š์•„ ๐Ÿ”ฅ

0๊ฐœ์˜ ๋Œ“๊ธ€