
์์ ๊ด๊ณ๋ is-a ๊ด๊ณ๋ผ๊ณ ๋ถ๋ฅด๊ณ ํฉ์ฑ ๊ด๊ณ๋ has-a ๊ด๊ณ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์์์ ๋ถ๋ชจ ํด๋์ค ์์ ๊ตฌํ๋ ์ฝ๋ ์์ฒด๋ฅผ ์ฌ์ฌ์ฉ ํ์ง๋ง ํฉ์ฑ์ ํฌํจ๋๋ ๊ฐ์ฒด์ ํผ๋ธ๋ฆญ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฌ์ฉํ๋ค. ๋ฐ๋ผ์ ์์ ๋์ ํฉ์ฑ์ ์ฌ์ฉํ๋ฉด ๊ตฌํ์ ๋ํ ์์กด์ฑ์ ์ธํฐํ์ด์ค์ ๋ํ ์์กด์ฑ์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋ค. ๋ค์ ๋งํด์ ํด๋์ค ์ฌ์ด์ ๋์ ๊ฒฐํฉ๋๋ฅผ ๊ฐ์ฒด ์ฌ์ด์ ๋ฎ์ ๊ฒฐํฉ๋๋ก ๋์ฒดํ ์ ์๋ ๊ฒ์ด๋ค.
์์์ ๋ฐ์ผ๋ฉด ๋ถ๋ชจ ํด๋์ค์ ๋ด๋ถ๊ฐ ์์ ํด๋์ค์ ๊ณต๊ฐ ๋๊ธฐ ๋๋ฌธ์ ํ์ดํธ๋ฐ์ค ์ฌ์ฌ์ฉ์ผ๋ก ๋ถ๋ฅธ๋ค. ํฉ์ฑ์ ๊ฐ์ฒด์ ๋ด๋ถ๋ ๊ณต๊ฐ ๋์ง ์๊ณ ์ธํฐํ์ด์ค๋ฅผ ํตํด์๋ง ์ฌ์ฌ์ฉ ๋๊ธฐ ๋๋ฌธ์ ๋ธ๋๋ฐ์ค ์ฌ์ฌ์ฉ์ผ๋ก ๋ถ๋ฅธ๋ค.
์ด์ ์ ์ฝ๋ ์ฌ์ฌ์ฉ์ ์ํด ์์์ ๋จ์ฉ ํ์ ๋ ์ง๋ฉดํ ์ ์๋ ์ธ ๊ฐ์ง ๋ฌธ์ ์ ์ ์ดํด๋ดค๋ค.
๋ถํ์ํ ์ธํฐํ์ด์ค ์์ ๋ฌธ์ : java.util.Properties์ java.util.Stack
๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋ฉ์ ์ค์์ฉ ๋ฌธ์ : java.util.HashSet์ ์์๋ฐ์ InstumentedHashSet
๋ถ๋ชจ ํด๋์ค์ ์์ ํด๋์ค์ ๋์ ์์ ๋ฌธ์ : Playlist๋ฅผ ์์๋ฐ์ PersonalPlaylist
์์์ผ๋ก ์ธํด ๊ฒฐํฉ๋๊ฐ ๋์์ง๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ๋ฌธ์ ์ ์ด ๋ฐ์ํ๋ค.
์ด์ฒ๋ผ ์์์ ๋จ์ฉ์ผ๋ก ํ๋์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ ์ํด ํ์ ์ด์์ผ๋ก ๋ง์ ์์ ํด๋์ค๋ฅผ ์ถ๊ฐํด์ผ ํ๋ ๊ฒฝ์ฐ๋ฅผ ๊ฐ๋ฆฌ์ผ ํด๋์ค ํญ๋ฐ(class explosion) ๋ฌธ์ ๋๋ ์กฐํฉ์ ํญ๋ฐ(combinational explosion) ๋ฌธ์ ๋ผ๊ณ ๋ถ๋ฅธ๋ค.
์์ ๊ด๊ณ๋ ์ปดํ์ผ ํ์์ ๊ฒฐ์ ๋๊ณ ๊ณ ์ ๋๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ์คํํ๋ ๋์ค์๋ ๋ณ๊ฒฝํ ์ ์๋ค. ๋ฐ๋ผ์ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์กฐํฉํด์ผ ํ๋ ์ค๊ณ์ ์์์ ์ด์ฉํ๋ฉด ๋ชจ๋ ์กฐํฉ ๊ฐ๋ฅํ ๊ฒฝ์ฐ ๋ณ๋ก ํด๋์ค๋ฅผ ์ถ๊ฐ ํด์ผ ํ๋ค.
ํด๋์ค ํญ๋ฐ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ํฉ์ฑ์ ์ฌ์ฉํ๋ ์ด์ ๋ ๋ฐํ์์ ๊ฐ์ฒด ์ฌ์ด์ ์์กด์ฑ์ ์์ ๋กญ๊ฒ ๋ณ๊ฒฝํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ํฉ์ฑ์ ์ฌ์ฉํ๋ฉด ๊ตฌํ ์์ ์ ์ ์ฑ ๋ค์ ๊ด๊ณ๋ฅผ ๊ณ ์ ์ํฌ ํ์๊ฐ ์์ผ๋ฉฐ ์คํ ์์ ์ ์ ์ฑ ๋ค์ ๊ด๊ณ๋ฅผ ์ ์ฐํ๊ฒ ๋ณ๊ฒฝํ ์ ์๊ฒ ๋๋ค.
Phone ํด๋์ค๋ฅผ ์์ฑํ๋ค.
public class Phone {
private RatePolicy ratepolicy;
private List<Call> calls = new ArrayList<>();
public Phone(RatePolicy ratePolicy) {
this.ratePolicy = ratePolicy;
}
public List<Call> getCalls() {
return Collections.unmodifiableList(calls);
}
public Money calculateFee() {
return ratePolicy.calculateFee(this);
}
}
Phone ํด๋์ค์์ ์ฌ์ฉํ๋ RatePolicy ํ์ ์ ์ธํฐํ์ด์ค๋ก ์ ์ํ๋ค.
public interface RatePolicy {
Money calculateFee(Phone phone);
}
RatePolicy๋ฅผ ๊ตฌํํ ์ถ์ ํด๋์ค๋ฅผ ์์ฑํ๋ค.
public abstract class BasicRatePolicy implements RatePolicy {
@Override
public Money calculateFee(Phone phone) {
Money result = Money.ZERO;
for(Call call : phone.getCalls()) {
result.plus(calculateCallFee(call));
}
return result;
}
abstract protected Money calculateCallFee(Call call);
}
์ถ์ ํด๋์ค๋ฅผ ์์๋ฐ์ ๊ตฌํ ํด๋์ค๋ฅผ ์ ์ํ๋ค.
public class RegularPolicy extends BasicRatePolicy {
private Money amout;
private Duration seconds;
public RegularPolicy(Money amount, Duration seconds) {
this.amount = amount;
this.seconds = seconds;
}
@Override
protected Money calculateCallFee(Call call) {
return amount.times(call.getDuration().getSeconds() / seconds.getSeconds());
}
}
์ด๋ฒ์ ๋ถ๊ฐ ์ฐ์ฐ์ ๊ตฌํํ ์ถ์ํด๋์ค๋ฅผ ์์ฑํด๋ณด์
public abstract class AdditionalRatePolicy implements RatePolicy {
private RatePolicy next;
public AdditionalRatePolicy(RatePolicy next) {
this.next = next;
}
@Override
public Money calculateFee(Phone phone) {
Money fee = next.calculateFee(phone);
return afterCalculated(fee);
}
abstract protected Money afterCalculated(Call call);
}
์ค์ ๋ก ํด๋ผ์ด์ธํธ์์๋ ๋ฐํ์์์ ๋ค์ํ ์กฐํฉ์ด ๊ฐ๋ฅํด์ง๋ค.
Phone phone = new Phone( new TexablePolicy(0.05,
new RateDiscountablePolicy(Money.wons(1000),
new RegularPolicy(...)));
๋ฏน์ค์ธ(mixin)์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์ฝ๋ ์ผ๋ถ๋ฅผ ํด๋์ค ์์ ์์ด ๋ฃ์ด ์ฌ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ ๊ฐ๋ฆฌํค๋ ์ฉ์ด๋ค. ํฉ์ฑ์ด ์คํ ์์ ์ ๊ฐ์ฒด๋ฅผ ์กฐํฉํ๋ ์ฌ์ฌ์ฉ ๋ฐฉ๋ฒ์ด๋ผ๋ฉด ๋ฏน์ค์ธ์ ์ปดํ์ผ ์์ ์ ํ์ํ ์ฝ๋ ์กฐ๊ฐ์ ์กฐํฉํ๋ ์ฌ์ฌ์ฉ ๋ฐฉ๋ฒ์ด๋ค.
์ฌ๊ธฐ๊น์ง ์ค๋ช ์ ๋ฃ๊ณ ๋๋ฉด ๋ฏน์ค์ธ๊ณผ ์์์ด ์ ์ฌํ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ฒ ์ง๋ง ๋ฏน์ค์ธ์ ์์๊ณผ๋ ๋ค๋ฅด๋ค. ์์์ ์ง์ ํ ๋ชฉ์ ์ ์์ ํด๋์ค๋ฅผ ๋ถ๋ชจ ํด๋์ค์ ๋์ผํ ๊ฐ๋ ์ ์ธ ๋ฒ์ฃผ๋ก ๋ฌถ์ด is-a ๊ด๊ณ๋ฅผ ๋ง๋ค๊ธฐ ์ํ ๊ฒ์ด๋ค. ๋ฐ๋ฉด ๋ฏน์ค์ธ์ ๋ง ๊ทธ๋๋ก ์ฝ๋๋ฅผ ๋ค๋ฅธ ์ฝ๋ ์์ ์์ด ๋ฃ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ด๋ค.
์ถ์ฒ
์ค๋ธ์ ํธ - ์ฝ๋๋ก ์ดํดํ๋ ๊ฐ์ฒด์งํฅ ์ค๊ณ
https://github.com/eternity-oop/object