Skip to content

Commit

Permalink
Merge pull request #267 from SujinEmilyCho/sujin
Browse files Browse the repository at this point in the history
[#2][2๊ธฐ] ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๋นŒ๋”๋ฅผ ๊ณ ๋ คํ•˜๋ผ
  • Loading branch information
ksy90101 authored May 16, 2021
2 parents 78b76c4 + 5bdc580 commit f5b9112
Showing 1 changed file with 318 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
# ์•„์ดํ…œ2. ์ƒ์„ฑ์ž์— ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๋นŒ๋”๋ฅผ ๊ณ ๋ คํ•˜๋ผ
์ •์  ํŒฉํ„ฐ๋ฆฌ์™€ ์ƒ์„ฑ์ž๋Š” ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์„ ๋•Œ ๋Œ€์‘ํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ด๋Ÿฐ ์ผ€์ด์Šค์— `์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด`, `์ž๋ฐ” ๋นˆ์ฆˆ ํŒจํ„ด`, `๋นŒ๋” ํŒจํ„ด`์„ ๊ณ ๋ คํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

### ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด(telescoping constructor pattern)

- ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ๋ฐ›๋Š” ์ƒ์„ฑ์ž, ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์„ ํƒ ๋งค๊ฐœ๋ณ€์ˆ˜ 1๊ฐœ๋ฅผ ๋ฐ›๋Š” ์ƒ์„ฑ์ž, ์„ ํƒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ 2๊ฐœ๊นŒ์ง€ ๋ฐ›๋Š” ์ƒ์„ฑ์ž, ..., ์„ ํƒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ „๋ถ€ ๋ฐ›๋Š” ์ƒ์„ฑ์ž๊นŒ์ง€ ๋Š˜๋ ค๊ฐ€๋Š” ๋ฐฉ์‹
- ํ™•์žฅํ•˜๊ธฐ ์–ด๋ ต๋‹ค
- ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฑฐ๋‚˜ ์ฝ๊ธฐ ์–ด๋ ต๋‹ค

```java
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, fat, 0);
}

public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium) {
this(servingSize, servings, 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;
}
}
```

```java
// ์ง€๋ฐฉ(fat)์— 0์„ ์ž‘์„ฑํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ ์„ค์ •ํ•˜๊ธธ ์›์น˜ ์•Š๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊นŒ์ง€ ๊ฐ’์„ ์ง€์ •ํ•ด์ค˜์•ผํ•œ๋‹ค.
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
```

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

- ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์—†๋Š” ์ƒ์„ฑ์ž๋กœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“  ํ›„, ์„ธํ„ฐ(setter) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์›ํ•˜๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ์‹
- ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์‰ฝ๊ณ  ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ง„๋‹ค
- ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋ฉ”์„œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๊ณ , ๊ฐ์ฒด๊ฐ€ ์™„์ „ํžˆ ์ƒ์„ฑ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ผ๊ด€์„ฑ(consistency)์ด ๋ฌด๋„ˆ์ง„ ์ƒํƒœ์— ๋†“์ธ๋‹ค(์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ผ๋Š” ์žฅ์น˜๊ฐ€ ์‚ฌ๋ผ์ง)
- ๋ถˆ๋ณ€์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†์œผ๋ฉฐ ์Šค๋ ˆ๋“œ ์•ˆ์ •์„ฑ์„ ์œ„ํ•œ ์ถ”๊ฐ€ ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค

```java
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 val) { servingSize = val; }
public void setServings(int val) { servings = val; }
public void setCalories(int val) { calories = val; }
public void setFat(int val) { fat = val; }
public void setSodium(int val) { sodium = val; }
public void setCarbohydrate(int val) {carbohydrate = val; }
}
```

```java
// ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์— ๋น„ํ•ด ํ™•์žฅํ•˜๊ธฐ ์‰ฝ๊ณ , ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ์‰ฝ๊ณ , ๊ฐ€๋…์„ฑ์ด ์ข‹์•„์ง„๋‹ค.
NutritinFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
```

### ๋นŒ๋” ํŒจํ„ด

- ํ•„์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ์ƒ์„ฑ์ž(ํ˜น์€ ์ •์  ํŒฉํ„ฐ๋ฆฌ)๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ƒ์„ฑ์„ ์œ„ํ•œ ๋นŒ๋” ๊ฐ์ฒด๋ฅผ ์–ป๊ณ , ๋นŒ๋” ๊ฐ์ฒด๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ผ์ข…์˜ ์„ธํ„ฐ ๋ฉ”์„œ๋“œ๋“ค๋กœ ์›ํ•˜๋Š” ์„ ํƒ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์„ค์ •. ๋งˆ์ง€๋ง‰์œผ๋กœ build ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด (๋ณดํ†ต์€ ๋ถˆ๋ณ€์ธ) ํƒ€๊ฒŸ ๊ฐ์ฒด๋ฅผ ์–ป๋Š” ๋ฐฉ์‹
- ๋นŒ๋”์˜ ์„ธํ„ฐ ๋ฉ”์„œ๋“œ๋“ค์€ ๋นŒ๋” ์ž์‹ ์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์„œ๋“œ ์—ฐ์‡„(method chaining)๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค(ํ”Œ๋ฃจ์–ธํŠธ API๋ผ๊ณ ๋„ ํ•œ๋‹ค)
- ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด์˜ ์•ˆ์ •์„ฑ(์œ ํšจ์„ฑ ๊ฒ€์‚ฌ)๊ณผ ์ž๋ฐ” ๋นˆ์ฆˆ ํŒจํ„ด์˜ ๊ฐ€๋…์„ฑ์ด๋ผ๋Š” ์žฅ์ ์„ ๊ฐ€์ง„๋‹ค
- ๋นŒ๋” ํ•˜๋‚˜๋กœ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋“ฑ ์œ ์—ฐํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
- ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ๋นŒ๋”๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด์•ผํ•˜๊ธฐ ๋–„๋ฌธ์— ์„ฑ๋Šฅ์— ๋ฏผ๊ฐํ•œ ์ƒํ™ฉ์—์„œ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค
- ์ ์ธต์  ์ƒ์„ฑ์ž ํŒจํ„ด๋ณด๋‹ค ์ฝ”๋“œ๊ฐ€ ์žฅํ™ฉํ•ด์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ 4๊ฐœ ์ด์ƒ์ผ ๋•Œ ์œ ์šฉํ•˜

```java
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; // ํ•„์ˆ˜
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;

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

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 NutirionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.fat;
carbohydrate = builder.carbohydrate;
}
}
```

```java
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27)
.build();
```

๋ถˆ๋ณ€(immutable) vs ๋ถˆ๋ณ€์‹(invariant)
- ๋ถˆ๋ณ€: ์–ด๋– ํ•œ ๋ณ€๊ฒฝ๋„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป, ์ฃผ๋กœ ๋ณ€๊ฒฝ์„ ํ—ˆ์šฉํ•˜๋Š” ๊ฐ€๋ณ€ ๊ฐ์ฒด์™€ ๊ตฌ๋ถ„ํ•˜๋Š” ์šฉ๋„๋กœ ์“ฐ์ธ๋‹ค. String์ด ๋Œ€ํ‘œ์ ์ธ ๋ถˆ๋ณ€ ๊ฐ์ฒด
- ๋ถˆ๋ณ€์‹: ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ, ํ˜น์€ ์ •ํ•ด์ง„ ๊ธฐ๊ฐ„ ๋™์•ˆ ๋ฐ˜๋“œ์‹œ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋Š” ์กฐ๊ฑด. ๋ณ€๊ฒฝ์„ ํ—ˆ์šฉํ•  ์ˆ˜๋Š” ์žˆ์œผ๋‚˜ ์ฃผ์–ด์ง„ ์กฐ๊ฑด ๋‚ด์—์„œ๋งŒ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๋œป. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฆฌ์ŠคํŠธ์˜ ํฌ๊ธฐ๋Š” ๋ฐ˜๋“œ์‹œ 0 ์ด์ƒ์ด์–ด์•ผ ํ•˜๋‹ˆ, ํ•œ ์ˆœ๊ฐ„์ด๋ผ๋„ ์Œ์ˆ˜ ๊ฐ’์ด ๋œ๋‹ค๋ฉด ๋ถˆ๋ณ€์‹์ด ๊นจ์ง„ ๊ฒƒ

### ๋นŒ๋” ํŒจํ„ด - ๊ณ„์ธต์  ๋นŒ๋”

- ๋นŒ๋” ํŒจํ„ด์€ ๊ณ„์ธต์ ์œผ๋กœ ์„ค๊ณ„๋œ ํด๋ž˜์Šค์™€ ํ•จ๊ป˜ ์“ฐ๊ธฐ ์ข‹๋‹ค
- ์ถ”์ƒ ํด๋ž˜์Šค์—๋Š” ์ถ”์ƒ ๋นŒ๋”๋ฅผ, ๊ตฌ์ฒด ํด๋ž˜์Šค์—๋Š” ๊ตฌ์ฒด ๋นŒ๋”๋ฅผ ์ž‘์„ฑ
- ํ•˜์œ„ ํด๋ž˜์Šค์˜ build ๋ฉ”์„œ๋“œ๋Š” ๊ตฌ์ฒด ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ ์–ธ(๊ณต๋ณ€ ๋ฐ˜ํ™˜ ํƒ€์ดํ•‘ - covariant return typing)
- ์ƒ์„ฑ์ž์™€ ๋‹ฌ๋ฆฌ ๊ฐ€๋ณ€ ์ธ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค(addTopping ๋ฉ”์„œ๋“œ)

```java
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();
}

abstarct Pizza build();

protected abstract T self(); // ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•ด์„œ this๋ฅผ ๋ฐ˜ํ™˜
}

Pizza(Builder<?> builder) {
toppings = builder.toppings.clone();
}
}
```

```java
public class NyPizza 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
public NyPizza build() {
return new NyPizza(this);
}

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

public NyPizza(Builder builder) {
super(builder);
size = builder.size;
}
}
}
```

```java
public class Calzone extends Pizza {
private final boolean sauceInside;

public static class Builder extends Pizza.Builder<Builder> {
private boolean sauceInsice = false;

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

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

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

private Calzone(Builder builder) {
super(builder);
sauceInside = builder.sauceInside;
}
}
}
```

```java
NyPizza pizza = new NyPizza.Builder(SMALL)
.addTopping(SAUSAGE)
.addTopping(ONION)
.build();

Calzone pizza = new Calzone.Builder()
.addTopping(HAM)
.sauceInside()
.build();
```

### ์ถ”๊ฐ€ ์˜ˆ์‹œ

```java
public class User {
private final int id; // ํ•„์ˆ˜
private final String name; //ํ•„์ˆ˜
private final Set<String> nicknames;
private final int phone;
private final String address;

private User(Builder builder) {
this.id = builder.id;
this.name = builder.name;
this.nicknames = builder.nicknames;
this.phone = builder.phone;
this.address = builder.address;
}

public static class Builder {
private final int id; // ํ•„์ˆ˜
private final String name; //ํ•„์ˆ˜
private final Set<String> nicknames = new HashSet<>();
private int phone;
private String address;

public Builder(int id, String name) {
this.id = id;
this.name = name;
}

public Builder nickname(String nickname) {
this.nicknames.add(nickname);
return this;
}

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

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

public User build() {
return new User(this);
}
}
}
```

### ์ •๋ฆฌ

์ƒ์„ฑ์ž๋‚˜ ์ •์  ํŒฉํ„ฐ๋ฆฌ๊ฐ€ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋งŽ๋‹ค๋ฉด ๋นŒ๋” ํŒจํ„ด์„ ์„ ํƒํ•˜๋Š” ๊ฒŒ ๋” ๋‚ซ๋‹ค. ๋งค๊ฐœ๋ณ€์ˆ˜ ์ค‘ ๋‹ค์ˆ˜๊ฐ€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹ˆ๊ฑฐ๋‚˜ ๊ฐ™์€ ํƒ€์ž…์ด๋ฉด ํŠนํžˆ ๋” ๊ทธ๋ ‡๋‹ค. ๋นŒ๋”๋Š” ์ ์ธต์  ์ƒ์„ฑ์ž๋ณด๋‹ค ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ์ฝ๊ณ  ์“ฐ๊ธฐ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ณ , ์ž๋ฐ”๋นˆ์ฆˆ๋ณด๋‹ค ํ›จ์”ฌ ์•ˆ์ „ํ•˜๋‹ค.

0 comments on commit f5b9112

Please sign in to comment.