๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

๐ŸŒˆ Chapter 11: ํ•ฉ์„ฑ๊ณผ ์œ ์—ฐํ•œ ์„ค๊ณ„

  • ํ•ฉ์„ฑ์€ ์ „์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ๋ถ€๋ถ„์„ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•ด์„œ ๋ถ€๋ถ„ ๊ฐ์ฒด์˜ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค. ๋˜ํ•œ, ํ•ฉ์„ฑ์—์„œ ๋‘ ๊ฐ์ฒด ์‚ฌ์ด์˜ ์˜์กด์„ฑ์€ ๋Ÿฐํƒ€์ž„์— ํ•ด๊ฒฐ๋œ๋‹ค.
  • ์ƒ์† ๊ด€๊ณ„๋Š” is-a ๊ด€๊ณ„๋ผ๊ณ  ๋ถ€๋ฅด๊ณ  ํ•ฉ์„ฑ ๊ด€๊ณ„๋Š” has-a ๊ด€๊ณ„๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
  • ํ•ฉ์„ฑ์€ ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์—์„œ ์ƒ์†๊ณผ ๋‹ค๋ฅด๋‹ค. ํ•ฉ์„ฑ์€ ๋‚ด๋ถ€์— ํฌํ•จ๋˜๋Š” ๊ฐ์ฒด์˜ ๊ตฌํ˜„์ด ์•„๋‹Œ ํผ๋ธ”๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ•ฉ์„ฑ์„ ์ด์šฉํ•˜๋ฉด ํฌํ•จ๋œ ๊ฐ์ฒด์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์ด ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€๊ฒฝ์— ๋” ์•ˆ์ •์ ์ธ ์ฝ”๋“œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
  • ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ์ ์— ๊ฒฐ์ •ํ•œ ์ƒ์† ๊ด€๊ณ„๋Š” ๋ณ€๊ฒฝ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ํ•ฉ์„ฑ ๊ด€๊ณ„๋Š” ์‹คํ–‰ ์‹œ์ ์— ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” ๊ฐ์ฒด ํ•ฉ์„ฑ์ด ํด๋ž˜์Šค ์ƒ์†๋ณด๋‹ค ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.

  • ์ƒ์†์€ ๋ถ€๋ชจ ํด๋ž˜์Šค ์•ˆ์— ๊ตฌํ˜„๋œ ์ฝ”๋“œ ์ž์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ•˜์ง€๋งŒ ํ•ฉ์„ฑ์€ ํฌํ•จ๋˜๋Š” ๊ฐ์ฒด์˜ ํผ๋ธ”๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ“š ์ƒ์†์„ ํ•ฉ์„ฑ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐโ€‹

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

๐ŸŽˆ ๋ถˆํ•„์š”ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์† ๋ฌธ์ œ: java.util.Properties์™€ java.util.Stackโ€‹

  • Vector๋ฅผ ์ƒ์†๋ฐ›๋Š” Stack์„ Vector์˜ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋ฅผ Stack ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•จ์œผ๋กœ์จ ํ•ฉ์„ฑ ๊ด€๊ณ„๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
public class Stack<E> {
private Vector<E> elements = new Vector()<>;

public E push(E item) {
elements.addElement(item);

return item;
}

public E pop() {
if (elements.isEmpty()) {
throw new EmptyStackException();
}

return elements.remove(elements.size() - 1);
}
}

๐ŸŽˆ ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์˜ ์˜ค์ž‘์šฉ ๋ฌธ์ œ: InstrumentHashSetโ€‹

  • InstrumentHashSet๋„ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์„œ ํ•ฉ์„ฑ ๊ด€๊ณ„๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • HashSet ์ธ์Šคํ„ด์Šค๋ฅผ ๋‚ด๋ถ€์— ํฌํ•จํ•œ ํ›„ HashSet์˜ ํผ๋ธ”๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜คํผ๋ ˆ์ด์…˜๋“ค์„ ์ด์šฉํ•ด ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ฉด ๋œ๋‹ค.
public class InstrumentHashSet<E> implements Set<E> {
private int addCount = 0;
private Set<E> set;

public InstrumentHashSet(Set<E> set) {
this.set = set;
}

@Override
public boolean add(E e) {
addCount++;

return set.add(e);
}

@Override
public boolean addAll(Collection<? extends E> c) {
addCount += c.size();

return set.addAll(c);
}

public int getAddCount() {
return addCount;
}

@Override public boolean remove(Object o) { return set.remove(o); }
@Override public void clear() { set.clear(); }
// ...
}
  • InstrumentHashSet์€ HashSet์ด ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. HashSet์€ Set ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‹ค์ฒดํ™”ํ•˜๋Š” ๊ตฌํ˜„์ฒด ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ, InstrumentHashSet์ด ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ๋ชจ๋“  ์˜คํผ๋ ˆ์ด์…˜๋“ค์€ Set ์ธํ„ฐํŽ˜์ด์Šค์— ์ •์˜๋ผ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ InstrumentHashSet์ด Set ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‹ค์ฒดํ™”ํ•˜๋ฉด์„œ ๋‚ด๋ถ€์— HashSet์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ•ฉ์„ฑํ•˜๋ฉด HashSet์— ๋Œ€ํ•œ ๊ตฌํ˜„ ๊ฒฐํ•ฉ๋„๋Š” ์ œ๊ฑฐํ•˜๋ฉด์„œ๋„ ํผ๋ธ”๋ฆญ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํฌ์›Œ๋”ฉ(forwarding)์ด๋ผ๊ณ  ๋ถ€๋ฅด๊ณ  ๋™์ผํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€๋œ ๋ฉ”์„œ๋“œ๋ฅผ ํฌ์›Œ๋”ฉ ๋ฉ”์„œ๋“œ(forwarding method)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

๐ŸŽˆ ๋ถ€๋ชจ ํด๋ž˜์Šค์™€ ์ž์‹ ํด๋ž˜์Šค์˜ ๋™์‹œ ์ˆ˜์ • ๋ฌธ์ œ: PersonalPlaylistโ€‹

  • ์ด๊ฒฝ์šฐ์—” ํ•ฉ์„ฑ์„ ์ด์šฉํ•˜์—ฌ ๋ณ€๊ฒฝํ•˜๋„๋ผ๋„ ๋‘ ํด๋ž˜์Šค์—์„œ ๋ณ€๊ฒฝ์ด ์ผ์–ด๋‚œ๋‹ค.
public class PersonalPlaylist {
private Playlist playlist = new Playlist();

public void append(Song song) {
// ...
}

public void remove(Song song) {
// ...
}
}
  • ๊ทธ๋ ‡๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ์—ฌ์ „ํžˆ ์ƒ์†๋ณด๋‹ค๋Š” ํ•ฉ์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์€๋ฐ ํ–ฅํ›„์— Playlist์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ๋ณ€๊ฒฝํ•˜๋”๋ผ๋„ ํŒŒ๊ธ‰ํšจ๊ณผ๋ฅผ ์ตœ๋Œ€ํ•œ PersonalPlaylist ๋‚ด๋ถ€๋กœ ์บก์Šํ™”ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
  • ๋ชฝํ‚ค ํŒจ์น˜
    ๋ชฝํ‚ค ํŒจ์น˜(Monkey Patch)๋ž€ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ํ™˜๊ฒฝ์—๋งŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๋„๋ก ์ง€์—ญ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค.
    Playlist์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ๊ถŒํ•œ์ด ์—†๊ฑฐ๋‚˜ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ๋ชฝํ‚ค ํŒจ์น˜๊ฐ€ ์ง€์›๋˜๋Š” ํ™˜๊ฒฝ์ด๋ผ๋ฉด Playlist์— ์ง์ ‘ remove ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (๋ฃจ๋น„์˜ ์—ด๋ฆฐ ํด๋ž˜์Šค, C#์˜ ํ™•์žฅ ๋ฉ”์„œ๋“œ)
  • ํ•ฉ์„ฑ์€ ์•ˆ์ •์„ฑ๊ณผ ์œ ์—ฐ์„ฑ์ด๋ผ๋Š” ์žฅ์ ์„ ์ œ๊ณตํ•œ๋‹ค.

๐Ÿ“š ์ƒ์†์œผ๋กœ ์ธํ•œ ์กฐํ•ฉ์˜ ํญ๋ฐœ์ ์ธ ์ฆ๊ฐ€โ€‹

  • ์ƒ์†์œผ๋กœ ์ธํ•ด ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์•„์ง€๋ฉด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ž‘์—…์˜ ์–‘์ด ๊ณผ๋„ํ•˜๊ฒŒ ๋Š˜์–ด๋‚˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค. (์ž‘์€ ๊ธฐ๋Šฅ๋“ค์„ ์กฐํ•ฉํ•ด์„œ ๋” ํฐ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ)
    • ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŽ์€ ์ˆ˜์˜ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.
    • ๋‹จ์ผ ์ƒ์†๋งŒ ์ง€์›ํ•˜๋Š” ์–ธ์–ด์—์„œ๋Š” ์ƒ์†์œผ๋กœ ์ธํ•ด ์˜คํžˆ๋ ค ์ค‘๋ณต ์ฝ”๋“œ์˜ ์–‘์ด ๋Š˜์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ๊ธฐ๋ณธ ์ •์ฑ…๊ณผ ๋ถ€๊ฐ€ ์ •์ฑ… ์กฐํ•ฉํ•˜๊ธฐโ€‹

  • 10์žฅ์—์„œ ์†Œ๊ฐœํ–ˆ๋˜ ํ•ธ๋“œํฐ ๊ณผ๊ธˆ ์‹œ์Šคํ…œ์— ์ƒˆ๋กœ์šด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ•ด๋ณธ๋‹ค.
  • ์ƒˆ๋กœ์šด ์š”๊ตฌ์‚ฌํ•ญ์€ ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์™€ ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ๋ผ๋Š” ๋‘ ์š”๊ธˆ์ œ์— ๋ถ€๊ฐ€ ์ •์ฑ…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. (๊ธฐ๋ณธ ์ •์ฑ…๊ณผ ๋ถ€๊ฐ€ ์ •์ฑ…)
  • ๋ถ€๊ฐ€ ์ •์ฑ…์€ ํ†ตํ™”๋Ÿ‰๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ๊ธฐ๋ณธ ์ €์ฑ…์— ์„ ํƒ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ์š”๊ธˆ ๋ฐฉ์‹.
  • ๋•Œ๋ฌธ์— ๋ถ€๊ฐ€ ์ •ใ…‡์ฑ…์€ ๊ธฐ๋ณธ ์ •์ฑ…์˜ ๊ณ„์‚ฐ ๊ฒฐ๊ณผ์— ์ ์šฉ๋  ์ˆ˜ ์žˆ๊ณ  ์„ ํƒ์ ์œผ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์กฐํ•ฉ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ, ๋ถ€๊ฐ€ ์ •์ฑ…์€ ์ž„์˜์˜ ์ˆœ์„œ๋กœ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๊ธฐ๋ณธ ์ •์ฑ… : ์ผ๋ฐ˜ ์š”๊ธˆ์ œ, ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ
  • ๋ถ€๊ฐ€ ์ •์ฑ… : ์„ธ๊ธˆ ์ •์ฑ…, ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…

๐ŸŽˆ ์ƒ์†์„ ์ด์šฉํ•ด์„œ ๊ธฐ๋ณธ ์ •์ฑ… ๊ตฌํ˜„ํ•˜๊ธฐโ€‹

  • 10์žฅ์˜ ์˜ˆ์ œ์™€ ๊ฐ™์Œ.

๐ŸŽˆ ๊ธฐ๋ณธ ์ •์ฑ…์— ์„ธ๊ธˆ ์ •์ฑ… ์กฐํ•ฉํ•˜๊ธฐโ€‹

  • ๋‹ค์Œ์€ ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ…์„ ์กฐํ•ฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ RegularPhone ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ TaxableRegularPhoneํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ ๊ฒƒ์ด๋‹ค.
public class TaxableRegularPhone extends RegularPhone {
private double taxRate;

public TaxableRegularPhone(Money amount, Duration seconds, double taxRate) {
super(amount, seconds);
this.taxRate = taxRate;
}

@Override
public Money calculateFee() { // ๋ถ€๋ชจ ํด๋ž˜์Šค์—์„œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ
Money fee = super.calculateFee();
return fee.plus(fee.times(taxRate)); // ์„ธ๊ธˆ ์ •์ฑ…์„ ์กฐํ•ฉํ•œ ์š”๊ธˆ์„ ๊ณ„์‚ฐ
}
}
  • super ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์‰ฝ๊ฒŒ ์–ป์„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ์ž์‹ ํด๋ž˜์Šค์™€ ๋ถ€๋ชจ ํด๋ž˜์Šค ์‚ฌ์ด์˜ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์•„์ง€๊ณ  ๋งŒ๋‹ค. ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๋Š” ๋ฐฉ๋ฒ•์€ ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋„๋ก ๋ถ€๋ชจ ํด๋ž˜์Šค์— ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
public abstract class Phone {
private List<Call> calls = new ArrayList<>();

public Money calculateFee() {
Money result = Money.ZERO;

for(Call call : calls) {
result = result.plus(calculateCallFee(call));
}

return afterCalculated(result);
}

protected abstract Money calculateCallFee(Call call);
protected abstract Money afterCalculated(Money fee);
}
  • ์ž์‹ ํด๋ž˜์Šค๋Š” afterCalculated ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์„œ ๊ณ„์‚ฐ๋œ ์š”๊ธˆ์— ์ ์šฉํ•  ์ž‘์—…์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
public class RegularPhone extends Phone {
// ...

@Override
protected Money calculateCallFee(Call call) {
return amount.times(call.getDuration().getSeconds() / seconds.getSeconds());
}

@Override
protected Money afterCalculated(Money fee) {
return fee;
}
}
  • NightlyDiscountPhone ํด๋ž˜์Šค ์—ญ์‹œ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.
public class NightlyDiscountPhone extends Phone {
// ...

@Override
protected Money calculateCallFee(Call call) {
if(call.getFrom().getHour() >= LATE_NIGHT_HOUR) {
return nightlyAmount.times(call.getDuration().getSeconds() / seconds.getSeconds());
} else {
return regularAmount.times(call.getDuration().getSeconds() / seconds.getSeconds());
}
}

@Override
protected Money afterCalculated(Money fee) {
return fee;
}
}
  • ์ด์ฒ˜๋Ÿผ ๋ถ€๋ชจ ํด๋ž˜์Šค์— ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ชจ๋“  ์ž์‹ ํด๋ž˜์Šค๋“ค์ด ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋ชจ๋“  ์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜ ๊ตฌํ˜„์ด ๋™์ผํ•˜๋‹ค. ์œ ์—ฐ์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ Phone์—์„œ afterCalculated ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ํ•จ๊ป˜ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ์ถ”์ƒ ๋ฉ”์„œ๋“œ์˜ ๋‹จ์ ์€ ์ƒ์† ๊ณ„์ธต์— ์†ํ•˜๋Š” ๋ชจ๋“  ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
public abstract class Phone {
// ...

protected Money afterCalculated(Money fee) { // ํ›… ๋ฉ”์„œ๋“œ
return fee;
}

protected abstract Money calculateCallFee(Call call);
}
  • ์ด์ฒ˜๋Ÿผ ์ถ”์ƒ ๋ฉ”์„œ๋“œ์™€ ๋™์ผํ•˜๊ฒŒ ์ž์‹ ํด๋ž˜์Šค์—์„œ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•  ์˜๋„๋กœ ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ ํŽธ์˜๋ฅผ ์œ„ํ•ด ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ›… ๋ฉ”์„œ๋“œ(hook method)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

  • TaxableRegularPhone์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

public class TaxableRegularPhone extends RegularPhone {
private double taxRate;

public TaxableRegularPhone(Money amount, Duration seconds, double taxRate) {
super(amount, seconds);
this.taxRate = taxRate;
}

@Override
public Money afterCalculated(Money fee) {
return fee.plus(fee.times(taxRate));
}
  • ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ์ธ NightDiscountPhone์—๋„ ์„ธ๊ธˆ์„ ๋ถ€๊ณผํ•  ์ˆ˜ ์žˆ๋„๋ก TaxableNightDiscountPhone์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
public class TaxableNightDiscountPhone extends NightlyDiscountPhone {
private double taxRate;

public TaxableNightDiscountPhone(Money nightlyAmount, Money regularAmount, Duration seconds, double taxRate) {
super(nightlyAmount, regularAmount, seconds);
this.taxRate = taxRate;
}

@Override
public Money afterCalculated(Money fee) {
return fee.plus(fee.times(taxRate));
}
  • ๋ฌธ์ œ๋Š” TaxableNightDiscountPhone๊ณผ TaxableRegularPhone ์‚ฌ์ด์— ์ฝ”๋“œ๋ฅผ ์ค‘๋ณตํ–ˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋‘ ํด๋ž˜์Šค์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์ด๋ฆ„์„ ์ œ์™ธํ•˜๋ฉด ๋Œ€๋ถ€๋ถ„ ์ฝ”๋“œ๊ฐ€ ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค.
  • ๋Œ€๋ถ€๋ถ„์˜ ๊ฐ์ฒด์ง€ํ–ฅ ์–ธ์–ด๋Š” ๋‹จ์ผ ์ƒ์†๋งŒ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์†์œผ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ์ค‘๋ณต ์ฝ”๋“œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค.

๐ŸŽˆ ๊ธฐ๋ณธ ์ •์ฑ…์— ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ… ์กฐํ•ฉํ•˜๊ธฐโ€‹

  • ๋‘ ๋ฒˆ์งธ ๋ถ€๊ฐ€ ์ •์ฑ…์ธ ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…์„ Phone์˜ ์ƒ์† ๊ณ„์ธต์— ์ถ”๊ฐ€ํ•ด๋ณธ๋‹ค.
  • ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์™€ ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…์„ ์กฐํ•ฉํ•˜๊ณ  ์‹ถ์œผ๋ฉด RegularPhone์„ ์ƒ์†๋ฐ›์€ RateDiscountableRegularPhone ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
public class RateDiscountableRegularPhone extends RegularPhone {
private Money discountAmount;

public RateDiscountableRegularPhone(Money amount, Duration seconds, Money discountAmount) {
super(amount, seconds);
this.discountAmount = discountAmount;
}

@Override
public Money afterCalculated(Money fee) {
return fee.minus(discountAmount);
}
  • ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ์™€ ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…์„ ์กฐํ•ฉํ•˜๊ณ  ์‹ถ์œผ๋ฉด NightlyDiscountPhone์„ ์ƒ์†๋ฐ›๋Š” RateDiscountableNightlyDiscountPhone ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.
public class RateDiscountableNightlyDiscountPhone extends NightlyDiscountPhone {
private Money discountAmount;

public RateDiscountableNightlyDiscountPhone(Money nightlyAmount, Money regularAmount, Duration seconds, Money discountAmount) {
super(nightlyAmount, regularAmount, seconds);
this.discountAmount = discountAmount;
}

@Override
public Money afterCalculated(Money fee) {
return fee.minus(discountAmount);
}
  • ์ด๋ฒˆ์—๋„ ๋ถ€๊ฐ€ ์ •์ฑ…์„ ๊ตฌํ˜„ํ•œ RateDiscountableNightlyDiscountPhone ํด๋ž˜์Šค์™€ RateDiscountableRegularPhone ํด๋ž˜์Šค ์‚ฌ์ด์— ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

๐ŸŽˆ ์ค‘๋ณต ์ฝ”๋“œ์˜ ๋ซ์— ๊ฑธ๋ฆฌ๋‹คโ€‹

  • ๋ถ€๊ฐ€ ์ •์ฑ…์€ ์ž์œ ๋กญ๊ฒŒ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ณ  ์ ์šฉ๋˜๋Š” ์ˆœ์„œ ์—ญ์‹œ ์ž„์˜๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ์ƒ์†์„ ์ด์šฉํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ์กฐํ•ฉ๋ณ„๋กœ ์ž์‹ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ต‰์žฅํžˆ ๋ณต์žกํ•ด์งˆ ๊ฒƒ์ด๋‹ค.
  • ํ•˜์ง€๋งŒ ๋ณต์žก์„ฑ๋ณด๋‹ค ๋” ํฐ ๋ฌธ์ œ๋Š” ๋ฐ”๋กœ ์ƒˆ๋กœ์šด ์ •์ฑ…์„ ์ถ”๊ฐ€ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ํ˜„์žฌ์˜ ์„ค๊ณ„์— ์ƒˆ๋กœ์šด ์ •์ฑ…์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ถˆํ•„์š”ํ•œ ๋งŽ์€ ์ˆ˜์˜ ํด๋ž˜์Šค๋ฅผ ์ƒ์† ๊ณ„์ธต ์•ˆ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
  • ์ƒ์†์˜ ๋‚จ์šฉ์œผ๋กœ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š” ์ด์ƒ์œผ๋กœ ๋งŽ์€ ์ˆ˜์˜ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ฐ€๋ฆฌ์ผœ ํด๋ž˜์Šค ํญ๋ฐœ(class explosion) ๋ฌธ์ œ ๋˜๋Š” ์กฐํ•ฉ์˜ ํญ๋ฐœ(combinational explosion) ๋ฌธ์ œ๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
  • ํด๋ž˜์Šค ํญ๋ฐœ ๋ฌธ์ œ๋Š” ์ž์‹ ํด๋ž˜์Šค๊ฐ€ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ตฌํ˜„์— ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜๋„๋ก ๊ฐ•์š”ํ•˜๋Š” ์ƒ์†์˜ ๊ทผ๋ณธ์ ์ธ ํ•œ๊ณ„ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋‹ค. ์ปดํŒŒ์ผํƒ€์ž„์— ๊ฒฐ์ •๋œ ์ž์‹ ํด๋ž˜์Šค์™€ ๋ถ€๋ชจ ํด๋ž˜์Šค ์‚ฌ์ด์˜ ๊ด€๊ณ„๋Š” ๋ณ€๊ฒฝ๋  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ž์‹ ํด๋ž˜์Šค์™€ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋‹ค์–‘ํ•œ ์กฐํ•ฉ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์—์„œ ์œ ์ผํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์กฐํ•ฉ์˜ ์ˆ˜๋งŒํผ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋ฟ์ด๋‹ค.
  • ํด๋ž˜์Šค ํญ๋ฐœ ๋ฌธ์ œ๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•  ๋•Œ๋„ ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค. ๋งŒ์•ฝ ์„ธ๊ธˆ ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด ๊ด€๋ จ๋œ ์ฝ”๋“œ๊ฐ€ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค ์•ˆ์— ์ค‘๋ณต๋ผ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ์ฐพ์•„ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค.
  • ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์„ ์˜ ๋ฐฉ๋ฒ•์€ ์ƒ์†์„ ํฌ๊ธฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๐Ÿ“š ํ•ฉ์„ฑ ๊ด€๊ณ„๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐโ€‹

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

๐ŸŽˆ ๊ธฐ๋ณธ ์ •์ฑ… ํ•ฉ์„ฑํ•˜๊ธฐโ€‹

  • ๋จผ์ € ๊ธฐ๋ณธ ์ •์ฑ…๊ณผ ๋ถ€๊ฐ€ ์ •์ฑ…์„ ํฌ๊ด„ํ•˜๋Š” RatePolicy ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. RatePolicy๋Š” Phone์„ ์ธ์ž๋กœ ๋ฐ›์•„ ๊ณ„์‚ฐ๋œ ์š”๊ธˆ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” calculateFee ์˜คํผ๋ ˆ์ด์…˜์„ ํฌํ•จํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.
public interface RatePolicy {
Money calculateFee(Phone phone);
}
  • ๊ธฐ๋ณธ ์ •์ฑ…์„ ๊ตฌ์„ฑํ•˜๋Š” ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์™€ ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ๋Š” ๊ฐœ๋ณ„ ์š”๊ธˆ์„ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ์‹์„ ์ œ์™ธํ•œ ์ „์ฒด ๋กœ์ง์ด ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค. ์ด ์ค‘๋ณต ์ฝ”๋“œ๋ฅผ ๋‹ด์„ ์ถ”์ƒ ํด๋ž˜์Šค BasicRatePolicy๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
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;
}

protected abstract Money calculateCallFee(Call call);
}
  • ๋‹ค์Œ์€ ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์˜ RegularPolicy ํด๋ž˜์Šค์ด๋‹ค.
public class RegularPolicy extends BasicRatePolicy {
// ...

@Override
protected Money calculateCallFee(Call call) {
return amount.times(call.getDuration().getSeconds() / seconds.getSeconds());
}
}
  • ๋‹ค์Œ์€ ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ์ธ NightlyDiscountPolicy ํด๋ž˜์Šค์ด๋‹ค.
public class NightlyDiscountPolicy extends BasicRatePolicy {
// ...

@Override
protected Money calculateCallFee(Call call) {
if(call.getFrom().getHour() >= LATE_NIGHT_HOUR) {
return nightlyAmount.times(call.getDuration().getSeconds() / seconds.getSeconds());
} else {
return regularAmount.times(call.getDuration().getSeconds() / seconds.getSeconds());
}
}
}
  • ์ด์ œ ๊ธฐ๋ณธ ์ •์ฑ…์„ ์ด์šฉํ•ด ์š”๊ธˆ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋„๋ก 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 Collection.unmodifiableList(calls);
}

public Money calculateFee() {
return ratePolicy.calculateFee(this);
}
}
  • ์ด๋•Œ Phone ๋‚ด๋ถ€์— RatePolicy์— ๋Œ€ํ•œ ์ฐธ์กฐ์ž๊ฐ€ ํฌํ•จ๋ผ ์žˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ํ•ฉ์„ฑ์ด๋‹ค. RatePolicy๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค. Phone์€ ๋Ÿฐํƒ€์ž„ ์˜์กด์„ฑ์œผ๋กœ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด RatePolicy์˜ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์˜์กด์„ฑ์„ ์ฃผ์ž…๋ฐ›๋Š”๋‹ค.
// ์ผ๋ฐ˜ ์š”๊ธˆ์ œ
Phone phone = new Phone(new RegularPolicy(Money.wons(10), Duration.ofSeconds(10)));

// ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ
Phone phone = new Phone(new NightlyDiscountPolicy(
Money.wons(5), Money.wons(10), Duration.ofSeconds(10)
));

๐ŸŽˆ ๋ถ€๊ฐ€ ์ •์ฑ… ์ ์šฉํ•˜๊ธฐโ€‹

  • ๋ถ€๊ฐ€ ์ •์ฑ…์€ RatePolicy ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋ฉฐ, ๋‚ด๋ถ€์— ๋˜ ๋‹ค๋ฅธ RatePolicy ์ธ์Šคํ„ด์Šค๋ฅผ ํ•ฉ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
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(Money fee);
}
  • ์„ธ๊ธˆ ์ •์ฑ… ๊ตฌํ˜„
public class TaxablePolicy extends AdditionalRatePolicy {
private double taxRatio;

public TaxablePolicy(double taxRatio, RatePolicy next) {
super(next);
this.taxRatio = taxRatio;
}

@Override
protected Money afterCalculated(Money fee) {
return fee.plus(fee.times(taxRatio));
}
}
  • ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…
public class RateDiscountablePolicy extends AdditionalRatePolicy {
private Money discountAmount;

public TaxablePolicy(Money discountAmount, RatePolicy next) {
super(next);
this.discountAmount = discountAmount;
}

@Override
protected Money afterCalculated(Money fee) {
return fee.minus(fee.times(taxRatio));
}
}

๐ŸŽˆ ๊ธฐ๋ณธ ์ „์ฑ…๊ณผ ๋ถ€๊ฐ€ ์ •์ฑ… ํ•ฉ์„ฑํ•˜๊ธฐโ€‹

  • ์ด์ œ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ •์ฑ…๋“ค์„ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ์„ค๊ณ„๊ฐ€ ์ค€๋น„๋๋‹ค.
// ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ… ์กฐํ•ฉ
Phone phone = new Phone(new TaxablePolicy(0.05, new RegularPolicy(...)));

// ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์— ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ…์„ ์กฐํ•ฉํ•œ ๊ฒฐ๊ณผ์— ์„ธ๊ธˆ ์ •์ฑ… ์กฐํ•ฉ
Phone phone = new Phone(new TaxablePolicy(0.05,
new RateDiscountablePolicy(Money.wons(1000),
new RegularPolicy(...)
)));

// ์ผ๋ฐ˜ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ… ์กฐํ•ฉํ•œ ๊ฒฐ๊ณผ์— ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ… ์กฐํ•ฉ
Phone phone = new Phone(new RateDiscountablePolicy(Money.wons(1000),
new TaxablePolicy(0.05,
new RegularPolicy(...)
)));

// ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ… ์กฐํ•ฉํ•œ ๊ฒฐ๊ณผ์— ๊ธฐ๋ณธ ์š”๊ธˆ ํ• ์ธ ์ •์ฑ… ์กฐํ•ฉ
Phone phone = new Phone(new RateDiscountablePolicy(Money.wons(1000),
new TaxablePolicy(0.05,
new NightlyDiscountPolicy(...)
)));

๐ŸŽˆ ์ƒˆ๋กœ์šด ์ •์ฑ… ์ถ”๊ฐ€ํ•˜๊ธฐโ€‹

  • ๋งŒ์•ฝ ๊ณ ์ • ์š”๊ธˆ์ œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ณ ์ • ์š”๊ธˆ์ œ๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค ํ•˜๋‚˜๋งŒ ์ถ”๊ฐ€ํ•œ ํ›„ ์›ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์กฐํ•ฉํ•˜๋ฉด ๋œ๋‹ค.
  • ์˜ค์ง ํ•˜๋‚˜์˜ ํด๋ž˜์Šค๋งŒ ์ถ”๊ฐ€ํ•˜๊ณ  ๋Ÿฐํƒ€์ž„์— ํ•„์š”ํ•œ ์ •์ฑ…๋“ค์„ ์กฐํ•ฉํ•ด์„œ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋” ์ค‘์š”ํ•œ ์ ์€ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ณ€๊ฒฝํ•  ๋•Œ ์˜ค์ง ํ•˜๋‚˜์˜ ํฌ๋ž˜์Šค๋งŒ ์ˆ˜์ •ํ•ด๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ค€์ˆ˜ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

๐ŸŽˆ ๊ฐ์ฒด ํ•ฉ์„ฑ์ด ํด๋ž˜์Šค ์ƒ์†๋ณด๋‹ค ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹คโ€‹

  • ์ƒ์†Œ์€ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ์„ธ๋ถ€์ ์ธ ๊ตฌํ˜„์— ์ž์‹ ํด๋ž˜์Šค๋ฅผ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ์˜ ์ง„ํ™”๋ฅผ ๋ฐฉํ•ดํ•œ๋‹ค.
  • ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฉด์„œ๋„ ๊ฑด์ „ํ•œ ๊ฒฐํ•ฉ๋„๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ํ•ฉ์„ฑ์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ƒ์†์ด ๊ตฌํ˜„์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ๋น„ํ•ด ํ•ฉ์„ฑ์€ ๊ฐ์ฒด์˜ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ“š ๋ฏน์Šค์ธโ€‹

  • ํ•ฉ์„ฑ์ด ์ƒ์†๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์ ์„ ์ดˆ๋ž˜ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ํด๋ž˜์Šค์˜ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์ด ์•„๋‹ˆ๋ผ ๊ฐ์ฒด์˜ ์ถ”์ƒ์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฉด์„œ๋„ ๋‚ฎ์€ ๊ฒฐํ•ฉ๋„๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ์žฌ์‚ฌ์šฉ์— ์ ํ•ฉํ•œ ์ถ”์ƒํ™”๋ฅผ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋ฏน์Šค์ธ(mixin)์€ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ฝ”๋“œ ์ผ๋ถ€๋ฅผ ํด๋ž˜์Šค ์•ˆ์— ์„ž์–ด ๋„ฃ์–ด ์žฌ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ฒ•์„ ๊ธฐ๋ฆฌํ‚ค๋Š” ์šฉ์–ด๋‹ค. ํ•ฉ์„ฑ์ด ์‹คํ–‰ ์‹œ์ ์— ๊ฐ์ฒด๋ฅผ ์กฐํ•ฉํ•˜๋Š” ์žฌ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด๋ผ๋ฉด ๋ฏน์Šค์ธ์€ ์ปดํŒŒ์ผ ์‹œ์ ์— ํ•„์š”ํ•œ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์กฐํ•ฉํ•˜๋Š” ์žฌ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์ด๋‹ค. ๋ฏน์Šค์ธ์€ ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ์ฝ”๋“œ ์•ˆ์— ์„ž์–ด ๋„ฃ๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์ƒ์†์ด ํด๋ž˜์Šค์™€ ํด๋ž˜์Šค ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๊ณ ์ •์‹œํ‚ค๋Š” ๋ฐ ๋น„ํ•ด ๋ฏน์Šค์ธ์€ ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๊ณ„๋ฅผ ์žฌ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฏน์Šค์ธ์€ ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์— ํŠนํ™”๋œ ๋ฐฉ๋ฒ•์ด๋ฉด์„œ๋„ ์ƒ์†๊ณผ ๊ฐ™์€ ๊ฒจํ•ฉ๋„ ๋ฌธ์ œ๋ฅผ ์ดˆ๋ž˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐ŸŽˆ ๊ธฐ๋ณธ ์ •์ฑ… ๊ตฌํ˜„ํ•˜๊ธฐโ€‹

  • ์Šค์นผ๋ผ๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ java์™€ ๋™์ผํ•จ์œผ๋กœ ์ƒ๋žต..

๐ŸŽˆ ํŠธ๋ ˆ์ดํŠธ๋กœ ๋ถ€๊ฐ€ ์ •์ฑ… ๊ตฌํ˜„ํ•˜๊ธฐโ€‹

  • ์Šค์นผ๋ผ์—์„œ๋Š” ๋‹ค๋ฅธ ์ฝ”๋“œ์™€ ์กฐํ•ฉํ•ด์„œ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ ํŠธ๋ ˆ์ดํŠธ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ถ€๊ฐ€ ์ •์ฑ… ์ค‘์—์„œ ์„ธ๊ธˆ ์ •์ฑ…์— ํ•ด๋‹นํ•˜๋Š” TaxablePolicy ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
trait TaxablePolicy extends BasicRatePolicy {
def taxRate: Double

override def calculateFee(phone: Phone): Money = {
val fee = super.calculateFee(phone)
return fee + fee * taxRate
}
}
  • ์œ„ ์ฝ”๋“œ์—์„œ TaxablePolicy ํŠธ๋ ˆ์ดํŠธ๊ฐ€ BasicRatePolicy๋ฅผ ํ™•์žฅํ•œ๋‹ค. ์ด๊ฒƒ์€ ์ƒ์†์˜ ๊ฐœ๋…์ด ์•„๋‹ˆ๋ผ TaxablePolicy๊ฐ€ BasicRatePolicy๋‚˜ BasicRatePolicy์˜ ์ž์†์— ํ•ด๋‹นํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ฏน์Šค์ธ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.
  • TaxablePolicy ํŠธ๋ ˆ์ดํŠธ๊ฐ€ BasicRatePolicy๋ฅผ ์ƒ์†ํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ TaxablePolicy๊ฐ€ BasicRatePolicy์˜ ์ž์‹ ํŠธ๋ ˆ์ดํŠธ๊ฐ€ ๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ์—์„œ extends ๋ฌธ์€ ๋‹จ์ง€ TaxablePolicy๊ฐ€ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋งฅ์„ ์ œํ•œํ•  ๋ฟ์ด๋‹ค. ์ฆ‰, TaxablePolicy๋Š” BasicRatePolicy๋ฅผ ์ƒ์†๋ฐ›๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ฏน์Šค์ธ๋  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด์ฒ˜๋Ÿผ ์ƒ์†์€ ์ •์ ์ด์ง€๋งŒ ๋ฏน์Šค์ธ์€ ๋™์ ์ด๋‹ค ์ƒ์†์€ ๋ถ€๋ชจ ํด๋ž˜์Šค์™€ ์ž์‹ ํด๋ž˜์Šค์˜ ๊ด€๊ณ„๋ฅผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์‹œ์ ์— ๊ณ ์ •์‹œ์ผœ ๋ฒ„๋ฆฌ์ง€๋งŒ ๋ฏน์Šค์ธ์€ ์ œ์•ฝ์„ ๋‘˜๋ฟ ์‹ค์ œ๋กœ ์–ด๋–ค ์ฝ”๋“œ์— ๋ฏน์Šค์ธ๋  ๊ฒƒ์ธ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ์‹ค์ œ๋กœ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๋ฏน์Šค์ธ ์‹œ์ ์— ๊ฐ€์„œ์•ผ ๋ฏน์Šค์ธํ•  ๋Œ€์ƒ์„ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฝ”๋“œ ์‚ฌ์ด์— ์–ด๋–ค ๊ด€๊ณ„๋„ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • super ์ฐธ์กฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋Œ€์ƒ์ด ์ปดํŒŒ์ผ ์‹œ์ ์ด ์•„๋‹Œ ์‹คํ–‰ ์‹œ์ ์— ๊ฒฐ์ •๋œ๋‹ค. ํŠธ๋ ˆ์ดํŠธ์˜ ๊ฒฝ์šฐ this ํ˜ธ์ถœ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ super ํ˜ธ์ถœ ์—ญ์‹œ ์‹คํ–‰ ์‹œ์ ์— ๋ฐ”์ธ๋”ฉ๋œ๋‹ค.
  • ํŠธ๋ ˆ์ดํŠธ๋Š” ๋ฌธ๋งฅ์„ ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋„๋ก ์—ด์–ด ๋†“๋Š”๋‹ค.
  • ํ•ฉ์„ฑ์€ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์„ฑ๋œ ๊ฐ์ฒด๋“ค์„ ์‹คํ–‰ ์‹œ์ ์— ์กฐํ•ฉํ•ด์„œ ๋” ํฐ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๋ฐ ๋น„ํ•ด ๋ฏน์Šค์ธ์€ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์„ฑ๋œ ํŠธ๋ ˆ์ดํŠธ์™€ ํด๋ž˜์Šค๋ฅผ ์ฝ”๋“œ ์ž‘์„ฑ ์‹œ์ ์— ์กฐํ•ฉํ•ด์„œ ๋” ํฐ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ๋ถ€๊ฐ€ ์ •์ฑ… ํŠธ๋ ˆ์ดํŠธ ๋ฏน์Šค์ธํ•˜๊ธฐโ€‹

  • ์Šค์นผ๋ผ๋Š” ํŠธ๋ ˆ์ดํŠธ๋ฅผ ํด๋ž˜์Šค๋‚˜ ๋‹ค๋ฅธ ํŠธ๋ ˆ์ดํŠธ์— ๋ฏน์Šค์ธํ•  ์ˆ˜ ์žˆ๋‹ค๋กœ๊ณ  extends์™€ with ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ํŠธ๋ ˆ์ดํŠธ์™€ ๋ฏน์Šค์ธํ•  ๋•Œ๋Š” with๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผ ํŠธ๋ ˆ์ดํŠธ ์กฐํ•ฉ์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
  • ํ‘œ์ค€ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ…์„ ์กฐํ•ฉํ•œ๋‹ค. ๋ฏน์Šค์ธํ•  ํŠธ๋ ˆ์ดํŠธ๋Š” TaxablePolicy์ด๊ณ  ์กฐํ•ฉ๋  ํด๋ž˜์Šค๋Š” RegularPolicy๋‹ค.
class TaxableRegularPolicy(
amount: Money,
seconds: Duration,
val taxRate: Double)
extends RegularPolicy(amount, seconds)
with TaxablePolicy
  • ์Šค์นผ๋ผ๋Š” ํŠน์ • ํด๋ž˜์Šค์— ๋ฏน์Šค์ธํ•œ ํด๋ž˜์Šค์™€ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์„ ํ˜•ํ™”(linearization)ํ•ด์„œ ์–ด๋–ค ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ• ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.
  • ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์Šค์นผ๋ผ๋Š” ํด๋ž˜์Šค ์ž์‹ ๊ณผ ์กฐ์ƒ ํด๋ž˜์Šค, ํŠธ๋ ˆ์ดํŠธ๋ฅผ ์ผ๋ ฌ๋กœ ๋‚˜์—ดํ•ด์„œ ์ˆœ์„œ๋ฅผ ์ •ํ•˜๊ณ , ์‹คํ–‰ ์ค‘์ธ ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ super ํ˜ธ์ถœ์„ ํ•˜๋ฉด ๋‹ค์Œ ๋‹จ๊ณ„์— ์œ„์น˜ํ•œ ํด๋ž˜์Šค๋‚˜ ํŠธ๋ ˆ์ดํŠธ์˜ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • ์„ ํ˜•ํ™”ํ•  ๋•Œ ํ•ญ์ƒ ๋งจ ์•ž์—๋Š” ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค ์ž๊ธฐ ์ž์‹ ์ด ์œ„์น˜ํ•œ๋‹ค. ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ TaxableRegularPolicy์ด๋‹ค. ๊ทธ ํ›„์— ์˜ค๋ฅธ์ชฝ์— ์„ ์–ธ๋œ ํŠธ๋ ˆ์ดํŠธ๋ฅผ ๊ทธ๋‹ค์Œ ์ž๋ฆฌ์— ์œ„์น˜์‹œํ‚ค๊ณ  ์™ผ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐ€๋ฉด์„œ ์ˆœ์„œ๋Œ€๋กœ ๊ทธ ์ž๋ฆฌ์— ์œ„์น˜์‹œํ‚จ๋‹ค. ์˜ˆ์ œ์˜ ๊ฒฝ์šฐ TaxableRegularPolicy ๋‹ค์Œ์— TaxablePolicy ํŠธ๋ ˆ์ดํŠธ, ๊ทธ ๋‹ค์Œ์— RegularPolicy๋ฅผ ์œ„์น˜์‹œํ‚จ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋ฏน์Šค์ธ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ƒ์† ๊ณ„์ธต ์•ˆ์—์„œ TaxablePolicy ํŠธ๋ ˆ์ดํŠธ์˜ ์œ„์น˜๊ฐ€ ๊ฒฐ์ •๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์œ„์น˜๊ฐ€ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.
  • ์‹ฌ์•ผ ํ• ์ธ ์š”๊ธˆ์ œ ๋˜‘๊ฐ™์ด ๋ฏน์Šค์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
class RateDiscountableNightlyDiscountPolicy(
nightlyAmount: Money,
regularAmount: Money,
seconds: Duration,
val discountAmount: Double)
extends NightlyDiscountPolicy(nightlyAmount, regularAmount, seconds)
with RateDiscountablePolicy
  • ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ ํ˜•ํ™”์˜ ํž˜์„ ๋นŒ๋ ค ์ž„์˜์˜ ์ˆœ์„œ์— ๋”ฐ๋ผ ์กฐํ•ฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
// ํ‘œ์ค€ ์š”๊ธˆ์ œ์— ์„ธ๊ธˆ ์ •์ฑ…์„ ์ ์šฉํ•œ ํ›„์— ๋น„์œจ ํ• ์ธ ์ •์ฑ…์„ ์ ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
class RateDiscountableAndTaxableRegularPolicy(
amount: Money,
seconds: Duration,
val discountAmount: Money,
val taxRate: Double)
extends RegularPolicy(amount, seconds)
with TaxablePolicy
with RateDiscountablePolicy

// ํ‘œ์ค€ ์š”๊ธˆ์ œ์— ๋น„์œจ ํ• ์ธ ์ •์ฑ…์„ ์ ์šฉํ•œ ํ›„์— ์„ธ๊ธˆ ์ •์ฑ…์„ ์ ์šฉํ•˜๋Š” ๊ฒฝ์šฐ
class TaxableAndRateDiscountableRegularPolicy(
amount: Money,
seconds: Duration,
val discountAmount: Money,
val taxRate: Double)
extends RegularPolicy(amount, seconds)
with RateDiscountablePolicy
with TaxablePolicy
  • ์ด์ฒ˜๋Ÿผ ๋ฏน์Šค์ธ์€ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์„ฑํ•œ ํ›„ ํ•„์š”ํ•œ ๊ณณ์—์„œ ์‰ฝ๊ฒŒ ์กฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽˆ ์Œ“์„ ์ˆ˜ ์žˆ๋Š” ๋ณ€๊ฒฝโ€‹

  • ๋ฏน์Šค์ธ์€ ์ƒ์† ๊ณ„์ธต ์•ˆ์—์„œ ํ™•์žฅํ•œ ํด๋ž˜์Šค๋ณด๋‹ค ๋” ํ•˜์œ„์— ์œ„์น˜ํ•˜๊ฒŒ ๋œ๋‹ค. ๋‹ค์‹œ ๋งํ•ด์„œ ๋ฏน์Šค์ธ ๋Œ€์ƒ ํด๋ž˜์Šค์˜ ์ž์‹ ํด๋ž˜์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋  ์šฉ๋„๋กœ ๋งŒ๋“ค์–ด์ง€๋Š” ๊ฒƒ์ด๋‹ค. TaxablePolicy์™€ RateDiscountablePolicy๋Š” BasicRatePolicy์— ์กฐํ•ฉ๋˜๊ธฐ ์œ„ํ•ด ํ•ญ์ƒ ์ƒ์† ๊ณ„์ธต์˜ ํ•˜์œ„์— ๋ฏน์Šค์ธ๋๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฏน์Šค์ธ์„ ์ถ”์ƒ ์„œ๋ธŒํด๋ž˜์Šค๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•œ๋‹ค.
  • ๋ฏน์Šค์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ •ํ•œ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ๋˜๋Š” ํ™•์žฅ์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌํ˜„ํ•œ ํ›„ ํ•„์š”ํ•œ ์‹œ์ ์— ์ฐจ๋ก€๋Œ€๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์ง•์„ ์Œ“์„ ์ˆ˜ ์žˆ๋Š” ๋ณ€๊ฒฝ(stackable modification)์ด๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.