# [Effective Java] Item 2. ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด Builder๋ฅผ ๊ณ ๋ คํ•˜์ž.
Study Repository

[Effective Java] Item 2. ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด Builder๋ฅผ ๊ณ ๋ คํ•˜์ž.

by rlaehddnd0422

์ •์  ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ, ์ค„์—ฌ์„œ ์ •ํŒฉ๋ฉ”์™€ ์ƒ์„ฑ์ž์€ ๋ชจ๋‘ ํ•œ ๊ฐ€์ง€ ์ œ์•ฝ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

> ๋ฐ”๋กœ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์„๋•Œ ์ ์ ˆํžˆ ๋Œ€์‘ํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ์ ์ธ๋ฐ์š”.

 

์ด ์ œ์•ฝ์— ๋Œ€ํ•œ ๋Œ€์•ˆ๋“ค์ด ์–ด๋–ค ๊ฒƒ๋“ค์ด ์žˆ๋Š”์ง€ ๋จผ์ € ํ•˜๋‚˜์”ฉ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด(Telescoping Constructor Pattern)

// ์˜์–‘ ์ •๋ณด ํด๋ž˜์Šค
public class NutritionFacts {

    private final int servingSize; //  ํ•„์ˆ˜
    private final int servings; // ํ•„์ˆ˜
    private final int calories; // ์„ ํƒ
    private final int fat; // ์„ ํƒ
    private final int sodium; // ์„ ํƒ
    private final int carbohydrate; // ์„ ํƒ

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories) {
        this(servingSize, servings, calories, 0);
    }


    public NutritionFacts(int servingSize, int servings, int calories, int fat) {
        this(servingSize, servings, calories, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}

 

  • ์˜์–‘์ •๋ณด๋ฅผ ๋‹ด๋Š” ํด๋ž˜์Šค NutritionFacts์ž…๋‹ˆ๋‹ค.
  • ์ด ํด๋ž˜์Šค๋Š” ํ”„๋กœํผํ‹ฐ๋กœ servingSize, servings, ... carbohydrate๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์„œ servingSize์™€ servings ํ”„๋กœํผํ‹ฐ๋Š” ํ•„์ˆ˜๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์•ผ ํ•˜๊ณ , ๋‚˜๋จธ์ง€ ํ”„๋กœํผํ‹ฐ๋Š” ๊ฐ’์„ ๊ผญ ๊ฐ€์ ธ์•ผ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์„ ํƒ์  ํ”„๋กœํผํ‹ฐ๋ผ๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ด๋Ÿฐ ๊ฒฝ์šฐ, ์ดˆ๊ธฐ ๊ฐœ๋ฐœ์ž๋“ค์€ ์œ„ ์ฝ”๋“œ์™€ ๊ฐ™์ด ์ƒ์„ฑ์ž๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ๋งค๊ฐœ๋ณ€์ˆ˜ 2๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž์—์„œ 3๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  3๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋Š” 4๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  4๊ฐœ๋Š” 5๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๊ฒฐ๊ตญ n-1๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๊ฐ€ n๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ณค ํ–ˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž ์ฝ”๋“œ๋งŒ ์ž‘์„ฑํ–ˆ์„ ๋ฟ์ธ๋ฐ ๋ฒŒ์จ ๋ฌด๊ฑฐ์›Œ์ง„ ๋Š๋‚Œ์ด๋„ค์š”.

NutritionFacts nutritionFacts = new NutritionFacts(10, 100, 0);

์ด ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์›ํ•˜๋Š” ์ด๋ ‡๊ฒŒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•œ ์ƒ์„ฑ์ž ์ค‘ ๊ฐ€์žฅ ์งง์€ ๊ฒƒ์„ ๊ณ ๋ฅด๋ฉด ๋˜๋Š”๋ฐ์š”. 

 

๋ณดํ†ต ์ด๋Ÿฐ ์ƒ์„ฑ์ž๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•˜๊ธธ ์›ํ•˜์ง€ ์•Š๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊นŒ์ง€ ํฌํ•จํ•˜๊ธฐ ์‰ฌ์šด๋ฐ, ๊ทธ๋Ÿฐ ๋งค๊ฐœ๋ณ€์ˆ˜์—๋„ ๊ฐ’์„ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ๋กœ ๋งํ•˜์ž๋ฉด fat ๋งค๊ฐœ๋ณ€์ˆ˜์— ๊ตณ์ด 0์˜ ๊ฐ’์„ ์„ค์ •ํ•ด์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ .

์ •๋ฆฌํ•˜์ž๋ฉด ์ด๋Ÿฐ ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด๋„ ์‚ฌ์šฉํ•  ์ˆ˜๋Š” ์žˆ๊ฒ ์ง€๋งŒ, ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ๋„ ์ฝ๊ธฐ๋„ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ์ฝ์„ ๋•Œ ๊ฐ ๊ฐ’์˜ ์˜๋ฏธ๋ฅผ ํŒŒ์•…ํ•ด์•ผ ํ•˜๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ช‡ ๊ฐœ์ธ์ง€๋„ ์ฃผ์˜ํ•ด์„œ ์„ธ์–ด๋ณด์•„์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€๋„ ์žˆ๊ณ , ํƒ€์ž…์ด ๊ฐ™์€ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—ฐ๋‹ฌ์•„ ์žˆ์œผ๋ฉด ์ฐพ๊ธฐ ์–ด๋ ค์šด ๋ฒ„๊ทธ๊ฐ€ ์ƒ๊ฒจ๋‚  ์ˆ˜๋„ ์žˆ๊ฒ ๊ตฌ์š”.

 

์ด๋ฒˆ์—๋Š” ๋‹ค๋ฅธ ๋Œ€์•ˆ์ธ ์ž๋ฐ”๋นˆ์ฆˆ ํŒจํ„ด์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 


์ž๋ฐ”๋นˆ์ฆˆ ํŒจํ„ด(JavaBeans Pattern)

์ž๋ฐ”๋นˆ์ฆˆ ํŒจํ„ด์„ ์ ์šฉํ•œ ์ฝ”๋“œ ๋จผ์ € ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

package dw.chapter1.item2;

// ์˜์–‘ ์ •๋ณด ํด๋ž˜์Šค
public class NutritionFacts {

    private  int servingSize = -1; //  ํ•„์ˆ˜
    private int servings = -1; // ํ•„์ˆ˜
    private int calories = 0; // ์„ ํƒ
    private int fat = 0;// ์„ ํƒ
    private int sodium = 0;// ์„ ํƒ
    private int carbohydrate = 0; // ์„ ํƒ

    public NutritionFacts() {}

    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }

    public void setServings(int servings) {
        this.servings = servings;
    }

    public void setCalories(int calories) {
        this.calories = calories;
    }

    public void setFat(int fat) {
        this.fat = fat;
    }

    public void setSodium(int sodium) {
        this.sodium = sodium;
    }

    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }
}
  • ๊ฐ ํ”„๋กœํผํ‹ฐ์— final ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์ด์ง€ ์•Š๊ณ , ์ดˆ๊ธฐ ๊ฐ’์„ ์„ธํŒ…ํ•˜๊ณ  setter๋ฅผ ์ž‘์„ฑํ•œ ํŒจํ„ด
  • ๊ฐ€๋…์„ฑ์ด ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์— ๋Œ€๋น„ํ•ด์„œ๋Š” ์ฝ๊ธฐ์—๋Š” ๋„ˆ๋ฌด ์‰ฝ๋‹ค๋Š” ์ ์ด ์žฅ์ ์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์˜ ๋‹จ์ (๋„ˆ๋ฌด ๋งŽ์€ ์ƒ์„ฑ์ž, ์ƒ์„ฑ์ž arugment์— ๋ถˆํ•„์š”ํ•œ ๊ฐ’ ์„ธํŒ…, ๋‚ฎ์€ ๊ฐ€๋…์„ฑ)์€ ์‚ฌ๋ผ์กŒ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ”„๋กœํผํ‹ฐ ์„ธํŒ…์„ setter๋กœ ํ•˜๋‚˜ํ•˜๋‚˜ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๋Š” ์ ๊ณผ ์•„๋ฌด๋ž˜๋„ setter๋ฅผ ์—ด์–ด๋‘์–ด ์ผ๊ด€์„ฑ์ด ๋ฌด๋„ˆ์กŒ๋‹ค๋Š” ์ ์œผ๋กœ ๋ณด์•„ ์ข‹์€ ํŒจํ„ด์œผ๋กœ ๋ณผ ์ˆ˜๋Š” ์—†์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ƒ์„ฑ์ด ๋๋‚œ ๊ฐ์ฒด๋ฅผ ์ˆ˜๋™์œผ๋กœ ์–ผ๋ฆฌ๊ณ  ์–ผ๋ฆฌ๊ธฐ ์ „์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋„๋ก ์„ค์ •ํ•˜์—ฌ ์ด๋Ÿฐ ๋‹จ์ ๋“ค์„ ์™„ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

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

 

๋งˆ์ง€๋ง‰ ๋Œ€์•ˆ์œผ๋กœ ๊ฐ€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 


Builder ํŒจํ„ด 

์ด Theme์—์„œ ๋งํ•˜๊ณ ์ž ํ•˜๋Š” ๋นŒ๋” ํŒจํ„ด์ด ๋งˆ์ง€๋ง‰ ๋Œ€์•ˆ์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค. 

 

๋นŒ๋” ํŒจํ„ด์€ ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด๊ณผ ์ž๋ฐ”๋นˆ์ฆˆ ํŒจํ„ด์˜ ์žฅ์ (์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์˜ ์•ˆ์ „์„ฑ, ์ž๋ฐ”๋นˆ์ฆˆ ํŒจํ„ด์˜ ๊ฐ€๋…์„ฑ)์„ ๋ชจ๋‘ ๊ฒธ๋น„ํ–ˆ๋‹ค๊ณ  ํ•˜๋Š”๋ฐ์š”. ๋จผ์ € ์ฝ”๋“œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

package dw.chapter1.item2;

// ์˜์–‘ ์ •๋ณด ํด๋ž˜์Šค
public class NutritionFacts {

    private final int servingSize; //  ํ•„์ˆ˜
    private final int servings; // ํ•„์ˆ˜
    private final int calories; // ์„ ํƒ
    private final int fat; // ์„ ํƒ
    private final int sodium; // ์„ ํƒ
    private final int carbohydrate; // ์„ ํƒ

    public static class Builder {

        // ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜
        private final int servingSize;
        private final int servings;

        // ์„ ํƒ ๋งค๊ฐœ๋ณ€์ˆ˜ - default ๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™”
        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int val) {
            calories = val;
            return this;
        }

        public Builder fat(int val) {
            fat = val;
            return this;
        }

        public Builder sodium(int val) {
            sodium = val;
            return this;
        }

        public Builder carbohydrate(int val) {
            carbohydrate = val;
            return this;
        }

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


    private NutritionFacts(Builder builder) {
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

 

  • NutritionFacts๋Š” ํ”„๋กœํผํ‹ฐ์— ๋ชจ๋‘ final ํ‚ค์›Œ๋“œ๋ฅผ ๋ถ™์—ฌ ๋ถˆ๋ณ€ ํด๋ž˜์Šค์ž„์„ ๋ณด์ฆํ•ด์ฃผ๋ฉด์„œ, ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ธฐ๋ณธ๊ฐ’๋“ค์„ ํ•œ ๊ณณ์— ๋ชจ์•„ ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

Builder์˜ ์„ธํ„ฐ ๋ฉ”์†Œ๋“œ๋“ค๋„ ๊ฒฐ๊ตญ ์ž์‹ ์„ ๋ฆฌํ„ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฉ”์†Œ๋“œ๋“ค์€ ์—ฐ์‡„์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! 

 

๊ทธ๋ž˜์„œ ๊ฒฐ๊ตญ ๋นŒ๋”๋ฅผ ์ ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

NutritionFacts nutritionFacts = new NutritionFacts.Builder(10, 100) // 3. ๋นŒ๋” ํŒจํ„ด
        .calories(10)
        .fat(100)
        .sodium(30)
        .carbohydrate(20)
        .build();
  • ๊ฐœ์ธ์ ์œผ๋กœ Lombok์˜ ์‚ฌ๊ธฐ์„ฑ์„ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ด์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ƒฅ @Builder ์–ด๋…ธํ…Œ์ด์…˜๋งŒ ๋ถ™์ด๋ฉด ์ด๋Ÿฐ ํŒจํ„ด์„ ์ž๋™์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ, ์–ด๋…ธํ…Œ์ด์…˜ ๋‚ด๋ถ€์—์„œ ์ด๋Ÿฐ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ์žˆ์—ˆ๋„ค์š”. ์ด ๋˜ํ•œ ์ฒ˜์Œ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. 

์ด๋ ‡๊ฒŒ ๊ฐ ์„ธํ„ฐ๊ฐ€ ์ž์‹ ์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๋•๋ถ„์— ๋ฉ”์†Œ๋“œ๋ฅผ ์—ฐ์‡„์ ์œผ๋กœ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ ์ด๋Ÿฐ ๋ฐฉ์‹์„ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹, ํ”Œ๋ฃจ์–ธํŠธ API๋ผ๊ณ  ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค!

 

๋ฌด์—‡๋ณด๋‹ค ์ด ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ๋„ ์ฝ๊ณ  ์“ฐ๊ธฐ ์‰ฝ๋‹ค๋Š” ํฐ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค๋งŒ,

 

๊ฐ ํ”„๋กœํผํ‹ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋Š”๋ฐ ์ด ๋‹จ์ ์€ ๊ทธ๋ƒฅ build() ๋ฉ”์†Œ๋“œ์—์„œ ๊ฐ ํ”„๋กœํผํ‹ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๊ณ  ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๋ฉ”์‹œ์ง€๋ฅผ ๋‹ด์•„ Un-Checked ์˜ˆ์™ธ๋ฅผ ๋˜์ ธ์คŒ์œผ๋กœ์จ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์˜ˆ์™ธ๋ฅผ ์•Œ๋ ค์ฃผ์–ด ์ถฉ๋ถ„ํžˆ ๋ณด์™„ํ•  ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ด ๋นŒ๋” ํŒจํ„ด์€ ๊ณ„์ธต์ ์œผ๋กœ ์„ค๊ณ„๋œ ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์“ฐ๊ธฐ์— ์ข‹์Šต๋‹ˆ๋‹ค.


๋นŒ๋” ํŒจํ„ด์„ ๊ณ„์ธต์ ์œผ๋กœ ์„ค๊ณ„๋œ ํด๋ž˜์Šค์— ์ ์šฉํ•ด๋ณด๊ธฐ

์ง€๊ธˆ๋ถ€ํ„ฐ๋Š” ์กฐ๊ธˆ ์–ด๋ ค์šด ๋‚ด์šฉ์ผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ตœ๋Œ€ํ•œ ์‰ฝ๊ฒŒ ํ’€์–ด๊ฐ€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ถ”์ƒ ํด๋ž˜์Šค๋Š” ์ถ”์ƒ ๋นŒ๋”๋ฅผ, ๊ตฌ์ฒด ํด๋ž˜์Šค๋Š” ๊ตฌ์ฒด ๋นŒ๋”๋ฅผ ๊ฐ–๊ฒŒ ํด๋ž˜์Šค๋ฅผ ์„ค๊ณ„ํ•œ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ถ”์ƒ ํด๋ž˜์Šค์—๋Š” ์ถ”์ƒ ๋นŒ๋”๋ฅผ

package dw.chapter1.item2;

import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

public abstract class Pizza {

    public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}

    final Set<Topping> toppings;

    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        // ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ this๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•ด์•ผํ•จ.
        protected abstract T self();

        abstract Pizza build();
    }

    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone();
    }
}
  • Pizza ๋Š” ํ”ผ์ž๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ถ”์ƒ ํด๋ž˜์Šค๋กœ ํ”ผ์ž ํ† ํ•‘์„ ์—ด๊ฑฐํ•˜๋Š” ์—ด๊ฑฐํ˜•(enum) ํƒ€์ž… Topping์ด ์žˆ๊ณ  ํด๋ž˜์Šค์—๋Š” ์ตœ์ข…์ ์ธ ํ† ํ•‘ ์ง‘ํ•ฉ์ธ EnumSet<Topping> toppings๋ฅผ ํ”„๋กœํผํ‹ฐ๋กœ ๊ฐ€์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์—ฌ๊ธฐ์— ๋”ํ•ด ์ถ”์ƒ ๋นŒ๋”๋„ ์ž‘์„ฑ์ด ๋˜์žˆ๋Š”๋ฐ, ์ถ”์ƒ ๋นŒ๋” ํด๋ž˜์Šค๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค.

abstract static class Builder<T extends Builder<T>> {
    EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

    public T addTopping(Topping topping) {
        toppings.add(Objects.requireNonNull(topping));
        return self();
    }

    // ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ this๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•ด์•ผํ•จ.
    protected abstract T self();
    
    abstract Pizza build();
}
  • ํƒ€์ž… ๋งค๊ฐœ๋ณ€์ˆ˜ T
    • Builder ํด๋ž˜์Šค๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž… T๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋นŒ๋” ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๋Š” ํ•˜์œ„ ํด๋ž˜์Šค์˜ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
  • toppings ํ•„๋“œ
    • EnumSet์„ ์‚ฌ์šฉํ•˜์—ฌ Topping ์—ด๊ฑฐํ˜•์˜ ํ† ํ•‘์„ ์ €์žฅํ•˜๋Š” ํ•„๋“œ์ž…๋‹ˆ๋‹ค.
    • EnumSet.noneOf(Topping.class)์„ ํ†ตํ•ด ์ดˆ๊ธฐํ™”๋˜์–ด ๋นˆ ์ƒํƒœ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
public T addTopping(Topping topping) {
    toppings.add(Objects.requireNonNull(topping));
    return self();
}
  • addTopping ๋ฉ”์†Œ๋“œ
    • ํ† ํ•‘์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ž…๋‹ˆ๋‹ค.
    • Objects.requireNonNull์„ ์‚ฌ์šฉํ•˜์—ฌ null ๊ฐ’์ด ์ „๋‹ฌ๋˜์ง€ ์•Š๋„๋ก ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • ๋ฉ”์†Œ๋“œ๋Š” ๋นŒ๋” ๊ฐ์ฒด ์ž์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ํ† ํ•‘์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
protected abstract T self();
  • ์—ฌ๊ธฐ์— ์ถ”์ƒ ๋ฉ”์†Œ๋“œ์ธ self๋ฅผ ๋”ํ•ด ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ๋Š” ํ˜•๋ณ€ํ™˜์„ ํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฉ”์†Œ๋“œ ์—ฐ์‡„๋ฅผ ์ง€์›ํ•  ์ˆ˜ ์žˆ์Œ
    • ํŒŒ์ด์ฌ๊ณผ ๋‹ฌ๋ฆฌ self ํƒ€์ž…์ด ์—†๋Š” ์ž๋ฐ”๋ฅผ ์œ„ํ•œ ์šฐํšŒ๋ฐฉ๋ฒ•์„ ์‹œ๋ฎฌ๋ ˆ์ดํŠธํ•œ ์…€ํ”„ ํƒ€์ž…์ด๋ผ๊ณ  ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค;
    • ๋ฉ”์†Œ๋“œ ์—ฐ์‡„๋ฅผ ์œ„ํ•ด ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ๋Š” ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜์—ฌ this๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.
abstract Pizza build();
  • ์‹ค์ œ๋กœ Pizza ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋กœ, ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ํ•˜์œ„ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„์ด ๋˜์–ด์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

 ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ๋ณด๋ฉด ์ข€ ๋” ์ดํ•ด๊ฐ€ ์‰ฌ์šธ์ˆ˜๋„ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์ถ”์ƒํด๋ž˜์Šค Pizza๋ฅผ ์ƒ์†๋ฐ›์€ ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ๋ด…์‹œ๋‹ค.

 

๊ตฌ์ฒด ํด๋ž˜์Šค์—์„œ๋Š” ์ถ”์ƒ ๋นŒ๋”๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌ์ฒด ๋นŒ๋” ๊ตฌํ˜„

package dw.chapter1.item2;

import java.util.Objects;

public class NewYorkPizza extends Pizza {

    public enum Size {SMALL, MEDIUM, LARGE}
    private final Size size;

    public static class Builder extends Pizza.Builder<Builder> {

        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override
        protected Builder self() {
            return this;
        }

        @Override
        public NewYorkPizza build() {
            return new NewYorkPizza(this);
        }
    }

    private NewYorkPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}
  • ๊ฐ ํ•˜์œ„ ํด๋ž˜์Šค์˜ ๋นŒ๋”๊ฐ€ ์ •์˜ํ•œ build ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ตฌ์ฒด ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ ์–ธํ•˜๊ธฐ
    • > NewYorkPizza.Builder๋Š” NewYork ํ”ผ์ž๋ฅผ ๋ฐ˜ํ™˜
    • > XXXPizza.Builder๋Š” XXXPizza๋ฅผ ๋ฐ˜ํ™˜ 
  • self() ๋ฉ”์†Œ๋“œ๋Š” ์ž๊ธฐ ์ž์‹ ์„ ๋ฆฌํ„ดํ•˜๋„๋ก ํ•˜๊ธฐ 
  • ํ•˜์œ„ ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์ •์˜ํ•œ ๋ฐ˜ํ™˜ ํƒ€์ž…์ด ์•„๋‹Œ(์œ„์˜ ์˜ˆ์‹œ๋กœ๋Š” Pizza๋ฅผ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ), ๊ทธ ํ•˜์œ„ ํƒ€์ž…์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ณต๋ณ€ ๋ฐ˜ํ™˜ ํƒ€์ดํ•‘์ด๋ผ๊ณ  ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ํ˜•๋ณ€ํ™˜์„ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  ๋นŒ๋”๋ฅผ ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค.

+ NewYorkPizza์™€ ๊ฐ™์€ ๋งฅ๋ฝ์˜ ๊ตฌ์ฒด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“  ์˜ˆ์‹œ(SeoulPizza)์ž…๋‹ˆ๋‹ค.

public class SeoulPizza extends Pizza {

    private final boolean sauceInside;

    public static class Builder extends Pizza.Builder<Builder> {

        private boolean sauceInside = false; // ๊ธฐ๋ณธ๊ฐ’

        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override
        protected Builder self() {
            return this;
        }

        @Override
        public SeoulPizza build() {
            return new SeoulPizza(this);
        }
    }

    private SeoulPizza(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}
  • ์ด์ œ๋Š” ๊ตฌ์ฒด ํด๋ž˜์Šค์— ์ถ”์ƒ ๋นŒ๋”์™€ ๊ตฌ์ฒด ๋นŒ๋”๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!
NewYorkPizza newYorkPizza = new NewYorkPizza
        .Builder(SMALL)
        .addTopping(SAUSAGE)
        .addTopping(ONION)
        .build();
        
SeoulPizza seoulPizza = new SeoulPizza
        .Builder()
        .addTopping(ONION)
        .sauceInside()
        .build();
  • ์ด๋ ‡๊ฒŒ ๋นŒ๋” ํŒจํ„ด์„ ์ ์šฉํ•˜๋ฉด ๊ณ„์ธตํ˜• ํด๋ž˜์Šค์—์„œ๋„ ์œ ์—ฐํ•˜๊ฒŒ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

๋นŒ๋” ํŒจํ„ด ๋‹จ์ 

๋ฌผ๋ก  ๋นŒ๋” ํŒจํ„ด์—๋„ ์žฅ์ ๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

  1. ๋นŒ๋” ํŒจํ„ด์„ ์ ์šฉํ•ด์„œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ๋นŒ๋”๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋Š” ์ 
  2. ์ฝ”๋“œ๊ฐ€ ์žฅํ™ฉํ•œ ๋งŒํผ ์ตœ์†Œ ๋งค๊ฐœ๋ณ€์ˆ˜ 4๊ฐœ์ด์ƒ์˜ ๋˜์–ด์•ผ ๊ฐ’์–ด์น˜๋ฅผ ํ•œ๋‹ค๋Š” ์ 
    1. ๋ฌผ๋ก  API๋Š” ์‹œ๊ฐ„์ด ์ง€๋‚ ์ˆ˜๋ก ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•˜๋ฉด ๋นŒ๋” ํŒจํ„ด์„ ๋จผ์ € ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„ ์ˆ˜ ์žˆ๊ฒ ๋‹ค.
    2. Item1์—์„œ๋Š” ๋Œ€๋†“๊ณ  ์ •ํŒฉ๋ฉ”๋ฅผ ๊ณ ๋ คํ•˜๋ผ๊ณ  ํ–ˆ์—ˆ์ง€๋งŒ, ์ ์  ํ”„๋กœํผํ‹ฐ๊ฐ€ ์ฆ๊ฐ€ํ•จ์— ๋”ฐ๋ผ ์ƒ์„ฑ ๋ฐฉ๋ฒ• ๋˜ํ•œ ๋Š˜์–ด๋‚˜ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ์šฐ๋ ค๊ฐ€ ์žˆ๋‹ค๋ฉด ์• ์ดˆ์— ๋นŒ๋”๋กœ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์ค‘์— ๊ณ ์ƒ์„ ๋œ ํ•˜์ง€ ์•Š์„๊นŒ .. ์ฑ… ์ €์ž์˜ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค.
    3. ํ•„์ž๋Š” Spring์—์„œ๋Š” ๋ณ„๋„์˜ ์‚ฌ์ „์ž‘์—… ์—†์ด ๋กฌ๋ณต ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด @Builder๋งŒ ๋ถ™์—ฌ์ฃผ๋ฉด ๋˜๋‹ˆ ๊ทธ๋ƒฅ ๋นŒ๋”๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค.

ํ•œ ์ค„ ์š”์•ฝ

์ƒ์„ฑ์ž, ์ •ํŒฉ๋ฉ”๊ฐ€ ์ฒ˜๋ฆฌํ•  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๋นŒ๋”๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ๋‚ซ๋‹ค.

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ