2-1 ์์ฑ์๋ฅผ ๋์ ํ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
by JiwonDev# ๊ฐ์
API๋ฅผ ์ฌ์ฉํ๋ ๊ฐ๋ฐ์๋ฅผ ์ฌ์ฉ์๋ผ๊ณ ์นญํ๋ค.
API๋ฅผ ์ฌ์ฉํ๋ ํด๋์ค๋ฅผ [๊ทธ API์ ํด๋ผ์ด์ธํธ]๋ผ๊ณ ์นญํ๋ค.
#1. ์์ฑ์๋ฅผ ๋์ ํ๋ ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋
๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๋ฉ์๋๋ฅผ Factory Method๋ผ๊ณ ํ๋ค.
[โ ์์ฑ์๋ฅผ ์ด์ฉํด์ ๊ฐ์ฒด๋ฅผ ๋ง๋๋๊ฒ] ๋์ ์ [โ Static Factory Method๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ]์ ์ฌ์ฉ์ ๊ณ ๋ คํ์.
์ฅ์
- ์ด๋ฆ์ ๊ฐ์ง ์ ์๋ค.
- ํธ์ถ๋ ๋๋ง๋ค ์ธ์คํด์ค๋ฅผ ์๋ก ์์ฑํ์ง ์์ ์๋ ์๋ค.
- ๋ฐํ ํ์ ์ ํ์ ํ์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์๋ ์๋ค.
- ์ ๋ ฅ ๋งค๊ฐ๋ณ์์ ๋ฐ๋ผ ๋งค๋ฒ ๋ค๋ฅธ ํด๋์ค์ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์๋ ์๋ค.
- ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์์ฑํ๋ ์์ ์๋ ๋ฐํํ ๊ฐ์ฒด์ ํด๋์ค๊ฐ ์กด์ฌํ์ง ์์๋ ๋๋ค.
๋จ์
- ์์์ ํ๋ ค๋ฉด public์ด๋ protected ์์ฑ์๊ฐ ํ์ํ๋ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ง ์ ๊ณตํ๋ฉด ํ์ ํด๋์ค๋ฅผ ๋ง๋ค์ ์๋ค. (๋ถ๋ณ ํ์ ์ผ๋ก ๋ง๋ค๊ฒฝ์ฐ ์คํ๋ ค ์ฅ์ ์ด ๋ ์ ์๋ค)
- ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ ํ๋ก๊ทธ๋๋จธ๊ฐ ํ์ธ์์ ์ด ํ์ํ๋ค.(์ฃผ์์ ๋ฌ์)
์ฃผ์์ฌํญ
- ์์ฑ์๋ง ์์ด๋ ์ถฉ๋ถํ ํด๋์ค์ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ์ฉํ๋ ๋ฐ๋ณด ์ง์ ํ์ง๋ง์.
- ๋ฉ์๋ ์ด๋ฆ(of, from...)์ ๋ํ ๊ท์ฝ์ด ์๋๊ฒ ์๋๋ผ์, ํฉํ ๋ฆฌ ๋ฉ์๋ ๊ธฐ๋ฅ์ ๋ํ ํ์คํ ์ ์๊ฐ ํ์ํ๋ค.
๐ ์์ฑ์ ์ค๋ฒ๋ก๋ฉ์ผ๋ก ๊ตฌํํ๋ฉด ์๋๋์? ์ ๊ตณ์ด Build()๋ฅผ ์ฌ์ฉํด์ผํ๋์?)
// ์ ์ธต์ ์์ฑ์ ํจํด - ๋ ๋ง์ ์ธ์ ๊ฐ์์ ์ ์ ์ํ์ง ๋ชปํ๋ค.
public class NutritionFacts {
private final int servingSize; // (mL) ํ์
private final int servings; // (per container) ํ์
private final int calories; // ์ ํ
private final int fat; // (g) ์ ํ
private final int sodium; // (mg) ์ ํ
private final int carbohydrate; // (g) ์ ํ
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, sodium, 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;
}
}
๋ถํธํ๋ค. ๊ทธ๋์ ์๋ฐ Bean ์์๋ ์๋์ ๊ฐ์ด ๋ณ๊ฒฝํ์๋ค.
// ์๋ฐ๋น ํจํด - ์ผ๊ด์ฑ ํผ์์ด ๊ฐ๋ฅํ๊ณ , ํญ์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ๋ค.
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() { }
// ์ค์ ์(setter)
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; }
}
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
์๋ฐ Bean์์ ์ฌ์ฉํ ๋ฐฉ๋ฒ์ ๋น๋ ํจํด๊ณผ ์ ์ฌํ๋ค.
ํ์ง๋ง ๊ฐ์ฒด์์ฑ์ดํ, Setter๋ก ๊ฐ์ ์ค์ ํ๋ ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ด ๊นจ์ง ์ ์๋ค.
๊ทธ๋์ ์๋์ ๊ฐ์ด ๊ฐ์ ํ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก ์ ์ ํฉํ ๋ฆฌ ๋ฉ์๋, ๋ด๋ถ ํด๋์ค Builder๋ฅผ ์ฌ์ฉํ๋ ํจํด์ด๋ค.
- ํ์ ์ธ์๋ค์ ์์ฑ์์(๋๋ ์ ์ ํฉํฐ๋ฆฌ ๋ฉ์๋์) ์ ๋ถ ์ ๋ฌํ์ฌ ๋น๋ ๊ฐ์ฒด(Builder object)๋ฅผ ๋ง๋ ๋ค.
- ๋น๋ ๊ฐ์ฒด์ ์ ์๋ ์ค์ ๋ฉ์๋๋ค์ ํธ์ถํ์ฌ ์ ํ์ ์ธ์๋ค์ ์ถ๊ฐํด ๋๊ฐ๋ค.
- ๋ง์ง๋ง์ผ๋ก ์๋ฌด๋ฐ ์ธ์ ์์ด build ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ณ๊ฒฝ ๋ถ๊ฐ๋ฅ(immutable) ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๊ฒ์ด๋ค.
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
// ๋น๋ ํจํด
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 = 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;
}
}
public static Item1 of(String name, String email) {
return Item1.builder()
.name(name)
.email(email)
.build();
}
public class Main{
public void main(){
//from: ๋งค๊ฐ๋ณ์๊ฐ 1๊ฐ์ผ ๊ฒฝ์ฐ,
Dog dog = Dog.from(name);
//of: ์ฌ๋ฌ ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ,
Dog dog = Dog.of(name, age);
//valueOf: from, of ๋ณด๋ค ์์ธํ ๋ฒ์ .
Dog dog = Dog.valueOf(name, age);
//getInstance: ์ธ์คํด์ค๋ฅผ ๋ฐํํ์ง๋ง, ๊ฐ์ ์ธ์คํด์ค์์ ๋ณด์ฅํ์ง ์์.
Dog dog = getInstance(age);
//newInstance: ๋งค๋ฒ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ฐํ.
Dog dog = Dog.newIncetance(name, age);
//getType: ๋ค๋ฅธ ํด๋์ค์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ.
Dog dog = Animal.getDog(name);
//newType: ๋ค๋ฅธ ํด๋์ค์ ํฉํฐ๋ฆฌ ๋ฉ์๋๋ฅผ ์ฌ์ฉ, ๋งค๋ฒ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ๋ฐํ.
Dog dog = Animal.newDog(name);
//getType, newType์ ๊ฐ๊ฒฐํ ๋ฒ์ .
Dog dog = Animal.dog(age);
}
}
@ ์ฅ์ 1-๋ฉ์๋์ ์ด๋ฆ์ ๊ฐ์ง ์ ์๋ค.
๋ฉ์๋์ ์ด๋ฆ์ ํตํด ๋ ์ฝ๊ธฐ ์ข์ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๋ค.
์์ฑ์์ ๋ค๋ฅด๊ฒ ๋ฉ์๋์ ์ด๋ฆ์ด ์์ผ๋ฏ๋ก ํ์ ์ด ์์ ํ ๊ฐ๋๋ผ๋ ๋ค๋ฅธ ๋์์ ํ๋ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ๋ง๋ค ์ ์๋ค.
@ ์ฅ์ 2-ํธ์ถ๋ ๋ ๋ง๋ค ์ธ์คํด์ค๋ฅผ ์๋ก ์์ฑํ์ง ์์๋ ๋๋ค.
์์ฑ์๋ฅผ Private๋ก ๋ง์๋๊ณ ์ธ์คํด์ค๋ฅผ ์ฌ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋ ๋ค. ์ฑ๊ธํค ๊ฐ์ฒด๋ก ๋ง๋ค ์ ์๋ค.
์ ์ ํฉํ ๋ฆฌ ๋ฐฉ์์ ํด๋์ค๋ ์ธ์คํด์ค์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ํต์ ํ ์ ์๋ค.
@ ์ฅ์ 3,4-์์ฑ์๋ฅผ ๋ง์์ผ๋ก์ ์ธํฐํ์ด์ค์ฒ๋ผ ํ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์์ฑ์ ์ญํ ์ ๋์ ํด์ฃผ๋ ํฉํ ๋ฆฌ ๋ฉ์๋๊ฐ ์๊น์ผ๋ก์, ์ธํฐํ์ด์ค์ฒ๋ผ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์์ ์ ์์ฑํ์ฌ ๋ฐํํ ํ์๊ฐ ์๋ค. ๊ฐ์ฒด๋ฅผ ์ธํฐํ์ด์ค์ฒ๋ผ ๋ง๋ค์ด๋๊ณ ํ์ํ์ , ์์๊ฐ์ฒด(๊ตฌํ์ฒด)๋ฅผ ๋ฐํํด๋ ๋๋ค.
โก ๊ตฌํํด๋์ค๋ฅผ ๊ณต๊ฐํ์ง ์๊ณ ๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํ ์ ์์ด ๊ณต๊ฐ๋ API๋ฅผ ์ ํํ๋ ํจ๊ณผ๊ฐ ์๋ค.
// Java8์ด์ ์๋ ์ธํฐํ์ด์ค ๋ด์์ Static, Default ๋ฉ์๋๋ฅผ ๊ฐ์ง ์ ์์๋ค.
// ๊ทธ๋์ Collection์ ์๋์ ๊ฐ์ด ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ๊ตฌํํ์์.
public class Collections {
// ์ธ์คํด์ค ์์ฑ๋ถ๊ฐ
private Collections() {
}
// ์ ์ ํํ ๋ฆฌ ๋ฉ์๋
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
}
// ๊ตฌํ์ฒด : non-public ์ด๋ค. ์์ ํ์
์ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ ๋ง๋ค ์ ์๋ค.
class UnmodifiableList<E> extends UnmodifiableCollection<E> implements List<E> {
...
}
โก Java8 ์์ interface ์์์ deafult, static ๋ฉ์๋์ ์ฌ์ฉ์ด ๊ฐ๋ฅํด์ง๋ฉด์, ์กฐ๊ธ ๋ ํธํ๊ฒ ๊ตฌํํ ์ ์๊ฒ ๋์๋ค.
public interface TestInterface {
void print();
static void getLowerType() {
TestExtendClass testExtendClass = new TestExtendClass();
testExtendClass.print();
}
}
// package-private์ผ๋ก ํด๋น ๊ตฌํ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค. ์์ ํ์
์ธ ์ธํฐํ์ด์ค์์ ์์ฑํ์ฌ ์ฌ์ฉํ๋ค.
class TestImplementsClass implements TestInterface {
@Override
public void print() {
System.out.println("print test");
}
}
@ ์ฅ์ 4- ์ฌ์ฉํ๊ธฐ ์ ๊น์ง ๋ฐํํ ๊ฐ์ฒด์ ํด๋์ค๊ฐ ์กด์ฌํ์ง ์์๋ ๋๋ค.
์์ฑ์๋ฅผ ๋ง๋ค์ด๋์ง ์๊ณ ์ฌ์ฉํ๋ ์์ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํด์ ๋ถํ์ํ ๊ฐ์ฒด์ ์์ฑ์ ๋ง๋๋ค.
String s = new String("hello"); // ์คํ๋ ๋ ๋ง๋ค ๊ฐ์ฒด๋ฅผ ์๋ก ๋ง๋ ๋ค.
String s = "hello" // ํ ๊ฐ์ฒด(์์)๋ฅผ ๋๊ณ ์ฌ์ฌ์ฉํ๋ค.
boolean isValue = str // ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๋ ๋ฐฉ์
Boolean.valueOf(str) // ํฉํ ๋ฆฌ ๋ฉ์๋ ๋ฐฉ์
ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ์ฑ๊ธํค๊ณผ ๋น์ทํ๊ฒ ๊ตฌํํ ์ ์๋ค. โก ์๋ฒฝํ ์ฑ๊ธํค์ ์ํ๋ค๋ฉด ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์.
2021.09.10 - [Backend/๋์์ธํจํด] - Singleton (์ฑ๊ธํค ํจํด)
public class Person {
private final Date birthDate;
// ๋ค๋ฅธ ํ๋์ ๋ฉ์๋, ์์ฑ์๋ ์๋ต
// ์ด๋ ๊ฒ ํ๋ฉด ์ ๋๋ค!
public boolean isBabyBoomer() {
// ์์ฑ ๋น์ฉ์ด ๋์ Date ๊ฐ์ฒด๋ฅผ ์ธ๋ฐ์์ด ์์ฑํ๋ค
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
}
public class Person {
private final Date birthDate;
// ๋ค๋ฅธ ํ๋์ ๋ฉ์๋, ์์ฑ์๋ ์๋ต
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 && birthDate.compareTo(BOOM_END) < 0;
}
}
# ์ค์ ์๋น์ค์์์ ์ฅ๋จ์
์ฅ์
- ๋งค๊ฐ๋ณ์๊ฐ ๋ง์ ๊ฒฝ์ฐ, ์ฝ๋๋ฅผ ์ฝ๊ณ ์ดํดํ๊ธฐ ๋งค์ฐ ์ฝ๋ค.
- setter๋ฅผ ์ด์ฉํ ๋ฐฉ์(์๋ฐ๋น์ฆ)์ ๊ฒฝ์ฐ, ๊ฐ์ฒด์ ๋ถ๋ณ์ฑ์ ๋ณด์ฅํ ์๊ฐ ์๋ค. public์ผ๋ก setter๊ฐ ๊ณต๊ฐ ๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด์ ๋นํด, ๋น๋ ํจํด์ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ ์ฝ๋ค.
- ๋น๋ ํจํด์ ๊ณ์ธต์ ์ผ๋ก ์ค๊ณ๋ ํด๋์ค์ ํจ๊ป ์ฐ๊ธฐ์ ์ข๋ค.
๋จ์
- ๋น๋ ํจํด์ ์ฝ๋๋์ด ๋ง๋ค. : @builder๋ ์ด๋ค๊ฐ, API๋ ์๊ฐ์ด ์ง๋ ์๋ก ๋งค๊ฐ๋ณ์๊ฐ ๋ง์ ์ง๊ฒ์ด๋ค.
- ๋น๋ํด๋์ค๋ฅผ ์์ฑํด์ผํ๋ค : ์ฑ๋ฅ์ ๋งค์ฐ ๋ฏผ๊ฐํ๋ค๋ฉด ๋ฌธ์ ๊ฐ ๋ ์๋ ์๋ค. ์ฌ์ฉํ์ง๋ ์๋ ๊ณณ์ ๋น๋๋ฅผ ๋ฃ์ง๋ง์.
'๐ฑBackend > Effective-Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
5-1 ์ ๋ค๋ฆญ์ ๊ทธ๋ฅ Raw ๋ก ์ฌ์ฉํ์ง ๋ง๋ผ(+ ๋น๊ฒ์ฌ ๊ฒฝ๊ณ ์ ๊ฑฐ) (0) | 2021.09.15 |
---|---|
4-1 ์์, ์ธํฐํ์ด์ค, ํด๋์ค์ ๊ถํ ์ต์ํ(+Java9 ๋ชจ๋) (0) | 2021.09.15 |
3-4 Cloneable์ ์ฌ์ฉํ์ง ๋ง๋ผ & Comparable์ ์ฌ์ฉ (0) | 2021.09.15 |
3-1 Equals์ toString์ ์ฌ์ ์ (0) | 2021.09.15 |
2-2 ๋ค ์ด ๊ฐ์ฒด์ฐธ์กฐ๋ฅผ ํด์ ํ๋ผ. (0) | 2021.09.15 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev