์ด์ ๊ธ์ ํตํด '์ ์ ์ด๊ฑฐ ํจํด์ ๋จ์ , ์ด๊ฑฐ ํ์ ์ ์ฅ์ , ์ด๊ฑฐ ํ์ ์ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ'์ ์์๋ณด์๋ค.
์ด๋ฒ ๊ธ์์๋ ์ด๊ฑฐ ํ์ ์ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ ๋ํด์ ์์๋ณด๋๋ก ํ์.
๐ 1. ์์๋ณ ๋ฉ์๋ ๊ตฌํ (constant-specific method implementation)
์ฌ์น์ฐ์ฐ ๊ณ์ฐ๊ธฐ์ ๊ฐ์ด ์์๋ง๋ค ๋์์ด ๋ฌ๋ผ์ ธ์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ๊ฐ์ฅ ๊ฐ๋จํ๊ฒ ์๊ฐํด ๋ณผ ์ ์๋ ๊ฒ์ switch๋ฌธ์ ํตํ์ฌ ๋ถ๊ธฐํ๋ ๋ฐฉ๋ฒ์ด๋ค.
public enum Operation {
PLUS, MINUS, TIMES, DIVIDE;
// ์์๊ฐ ๋ปํ๋ ์ฐ์ฐ์ ์ํํ๋ค.
public double apply(double x, double y) {
switch(this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
}
throw new AssertionError("์ ์ ์๋ ์ฐ์ฐ: " + this);
}
}
๋์์ ํ์ง๋ง ์ข์ ์ฝ๋๋ ์๋๋ค. ๋ง์ง๋ง์ throw ๋ฌธ์ ์ค์ ๋ก๋ ๋๋ฌํ ์ผ์ด ์์ง๋ง ๊ธฐ์ ์ ์ผ๋ก๋ ๋๋ฌํ ์ ์๊ธฐ ๋๋ฌธ์ ์๋ตํ๋ฉด ์ปดํ์ผ์กฐ์ฐจ ๋์ง ์๋๋ค.
๋ํ, ์๋ก์ด ์์๋ฅผ ์ถ๊ฐํ๋ฉด ํด๋น case ๋ฌธ๋ ์ถ๊ฐํด์ผ ํ๋ฏ๋ก ๊นจ์ง๊ธฐ ์ฌ์ด ์ฝ๋์ด๋ค. ์๋ก์ด ์์๋ฅผ ์ถ๊ฐํ์ง๋ง case ๋ฌธ์ ์ฐ์ฐ์ ์ถ๊ฐํ์ง ์์ ๊ฒฝ์ฐ ์ปดํ์ผ์ ๋๋ค. ํ์ง๋ง, ์๋ก ์ถ๊ฐํ ์ฐ์ฐ์ ์ํํ๋ ค ํ ๋ "์ ์ ์๋ ์ฐ์ฐ"์ด๋ผ๋ ๋ฐํ์ ์ค๋ฅ๋ฅผ ๋ด๋ฉฐ ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋๋ค.
์ด๊ฑฐ ํ์ ์ ์์๋ณ ๋ฉ์๋ ๊ตฌํ ๋ฐฉ์์ ์ด์ฉํ๋ฉด ์์๋ณ๋ก ๋ค๋ฅด๊ฒ ๋์ํ๋ ์ฝ๋๋ฅผ ๊ตฌํํ ์ ์๋ค.
์ด๊ฑฐ ํ์ ์ apply๋ผ๋ ์ถ์ ๋ฉ์๋๋ฅผ ์ ์ธํ๊ณ ๊ฐ ์์๋ณ๋ก ํด๋์ค ๋ชธ์ฒด(constant-specific class body)๋ฅผ ์ฌ์ ์ํ๋ฉด ๋๋ค.
public enum Operation {
PLUS {
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
public double apply(double x, double y) {
return x - y;
}
},
TIMES {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
public double apply(double x, double y) {
return x / y;
}
};
public abstract double apply(double x, double y);
}
์ด๋ ๊ฒ ํ๋ฉด ์๋ก์ด ์์๋ฅผ ์ถ๊ฐํ ๋ apply๋ ์ฌ์ ์ํด์ผ ํ๋ค๋ ์ฌ์ค์ ๊น๋นกํ๊ธฐ๋ ์ด๋ ค์ธ ๊ฒ์ด๋ค. ๋ํ, apply๊ฐ ์ถ์ ๋ฉ์๋์ด๋ฏ๋ก ์ฌ์ ์ํ์ง ์์๋ค๋ฉด ์ปดํ์ผ ์ค๋ฅ๋ก ์๋ ค์ค๋ค.
๐ 2. toString ๋ฉ์๋ & fromString ๋ฉ์๋
์์๋ณ ๋ฉ์๋ ๊ตฌํ์ ์์๋ณ ๋ฐ์ดํฐ์ ๊ฒฐํฉํ ์๋ ์๋ค. ๋ค์๊ณผ ๊ฐ์ด Operation์ toString์ ์ฌ์ ์ํด ํด๋น ์ฐ์ฐ์ ๋ปํ๋ ๊ธฐํธ๋ฅผ ๋ฐํํ๋๋ก ํ ์ ์๋ค.
public enum Operation {
PLUS("+") {
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public abstract double apply(double x, double y);
}
public static void main(String[] args) {
double x = 2d;
double y = 4d;
for(Operation op : Operation.values()) {
System.out.printf("%f %s %f = %f\n", x, op, y, op.apply(x, y));
}
// ๊ฒฐ๊ณผ
// 2.000000 + 4.000000 = 6.000000
// 2.000000 - 4.000000 = -2.000000
// 2.000000 * 4.000000 = 8.000000
// 2.000000 / 4.000000 = 0.500000
}
์ด๊ฑฐ ํ์ ์๋ ์์ ์ด๋ฆ์ ์ ๋ ฅ๋ฐ์ ๊ทธ ์ด๋ฆ์ ํด๋นํ๋ ์์๋ฅผ ๋ฐํํด ์ฃผ๋ valueOf(String) ๋ฉ์๋๊ฐ ์๋ ์์ฑ๋๋ค.
public static void main(String[] args) {
Operation plus = Operation.valueOf("PLUS");
System.out.println(plus); // +
}
๋ํ, toString์ด ๋ฐํํ๋ ๋ฌธ์์ด์ ํด๋น ์ด๊ฑฐ ํ์ ์์๋ก ๋ณํํด ์ฃผ๋ fromString ๋ฉ์๋๋ ํจ๊ป ์ ๊ณตํ ์ ์๋ค.
public enum Operation {
PLUS("+") {
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public abstract double apply(double x, double y);
private static final Map<String, Operation> stringToEnum =
Stream.of(values()).collect(
toMap(Object::toString, e -> e));
// ์ง์ ํ ๋ฌธ์์ด์ ํด๋นํ๋ Operation์ (์กด์ฌํ๋ค๋ฉด) ๋ฐํํ๋ค.
public static Optional<Operation> fromString(String symbol) {
return Optional.ofNullable(stringToEnum.get(symbol));
}
}
public static void main(String[] args) {
Optional<Operation> plusFromString = Operation.fromString("+");
System.out.println(plusFromString.get()); // +
}
Operation ์์๊ฐ stringToEnum ๋งต์ ์ถ๊ฐ๋๋ ์์ ์ ์ด๊ฑฐ ํ์ ์์ ์์ฑ ํ ์ ์ ํ๋๊ฐ ์ด๊ธฐํ๋ ๋๋ค.
๐ 3. ์ ๋ต ์ด๊ฑฐ ํ์
์์๋ณ ๋ฉ์๋ ๊ตฌํ์๋ ์ด๊ฑฐ ํ์
์์๋ผ๋ฆฌ ์ฝ๋๋ฅผ ๊ณต์ ํ๊ธฐ ์ด๋ ต๋ค๋ ๋จ์ ์ด ์๋ค.
๋ค์์ ๊ธ์ฌ๋ช
์ธ์์์ ์ฌ์ฉํ ์์ผ์ ํํํ๋ ์ด๊ฑฐ ํ์
์ด๋ค. ์ง์์ (์๊ฐ๋น) ๊ธฐ๋ณธ์๊ธ๊ณผ ๊ทธ๋ ์ผํ ์๊ฐ(๋ถ ๋จ์)์ด ์ฃผ์ด์ง๋ฉด ์ผ๋น์ ๊ณ์ฐํด ์ฃผ๋ ๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์ฃผ์ค์๋ ์ค๋ฒํ์๋งํผ ์์
์๋น์ด ์ฃผ์ด์ง๊ณ , ์ฃผ๋ง์๋ ๋ฌด์กฐ๊ฑด ์์
์๋น์ด ์ฃผ์ด์ง๋ค.
public enum PayrollDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY,
SATURDAY, SUNDAY;
private static final int MINS_PER_SHIFT = 8 * 60; // 8์๊ฐ
int pay(int minutesWorked, int payRate) {
int basePay = minutesWorked * payRate;
int overtimePay;
switch(this) {
case SATURDAY: // ์ฃผ๋ง (๋ฌด์กฐ๊ฑด ์์
์๋น์ผ๋ก ๊ณ์ฐ)
case SUNDAY:
overtimePay = basePay / 2;
break;
default: // ์ฃผ์ค (8์๊ฐ ์ด๊ณผ์ ์์
์๋น ์ฃผ์ด์ง)
overtimePay = minutesWorked <= MINS_PER_SHIFT ?
0 : (minutesWorked - MINS_PER_SHIFT) * payRate / 2;
}
return basePay + overtimePay;
}
}
์ด ์ฝ๋๋ ๊ด๋ฆฌ ๊ด์ ์์ ์ํํ ์ฝ๋์ด๋ค. ํด๊ฐ์ ๊ฐ์ ์๋ก์ด ๊ฐ์ ์ด๊ฑฐ ํ์ ์ ์ถ๊ฐํ๋ ค๋ฉด ๊ทธ ๊ฐ์ ์ฒ๋ฆฌํ๋ case ๋ฌธ์ ์์ง ๋ง๊ณ ์์ผ๋ก ๋ฃ์ด์ค์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
ํด๋น ๋ฌธ์ ์ ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์๋ก์ด ์์๋ฅผ ์ถ๊ฐํ ๋ ์์ ์๋น '์ ๋ต'์ ์ ํํ๋๋ก ํ ์ ์๋ค.
public enum PayrollDay {
MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY), THURSDAY(WEEKDAY), FRIDAY(WEEKDAY),
SATURDAY(WEEKEND), SUNDAY(WEEKEND);
private final PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
int pay(int minutesWorked, int payRate) {
return payType.pay(minutesWorked, payRate);
}
// ์ ๋ต ์ด๊ฑฐ ํ์
enum PayType {
WEEKDAY {
int overtimePay(int minsWorked, int payRate) {
return minsWorked <= MINS_PER_SHIFT ? 0 :
(minsWorked - MINS_PER_SHIFT) * payRate / 2;
}
},
WEEKEND {
int overtimePay(int minsWorked, int payRate) {
return minsWorked * payRate / 2;
}
};
abstract int overtimePay(int mins, int payRate);
private static final int MINS_PER_SHIFT = 8 * 60;
int pay(int minsWorked, int payRate) {
int basePay = minsWorked * payRate;
return basePay + overtimePay(minsWorked, payRate);
}
}
}
์ด ๋ฐฉ๋ฒ์ ์์ ์๋น ๊ณ์ฐ์ private ์ค์ฒฉ ์ด๊ฑฐ ํ์ (์๋์ PayType)์ผ๋ก ์ฎ๊ธฐ๊ณ PayrollDay ์ด๊ฑฐ ํ์ ์ ์์ฑ์์์ ์ด ์ค ์ ๋นํ ๊ฒ์ ์ ํํ๋ค.
๊ทธ๋ฌ๋ฉด PayrollDay ์ด๊ฑฐ ํ์ ์ ์์ ์๋น ๊ณ์ฐ์ ๊ทธ ์ ๋ต ์ด๊ฑฐ ํ์ ์ ์์ํ์ฌ, switch ๋ฌธ์ด๋ ์์๋ณ ๋ฉ์๋ ๊ตฌํ์ด ํ์ ์๊ฒ ๋๋ค.
์์์ ์ดํด๋ณธ switch ๋ฌธ์ ์ด์ฉํ๋ ๋ฐฉ๋ฒ๋ณด๋ค ๋ณต์กํ์ง๋ง ๋ ์์ ํ๊ณ ์ ์ฐํ๋ค.
ํด๋น ๊ธ์ Joshua Bloch ๋์ 'Effective Java 3/E'๋ฅผ ์ฐธ๊ณ ํ์์ต๋๋ค.