Visitor Pattern(๋น์งํฐ ํจํด)
๊ฐ์ฒด
(๋ฐ์ดํฐ ๊ตฌ์กฐ)์ ๋ก์ง
(์๊ณ ๋ฆฌ์ฆ)์ ๋ถ๋ฆฌํ๋ ๋์์ธ ํจํด
์๋ก์ด ๋ก์ง์ ์ถ๊ฐํ๋๋ผ๋ ๊ฐ์ฒด์ ๊ตฌ์กฐ๋ ๋ณ๊ฒฝํ์ง ์์ ์ฑ ์๋ก์ด ๋์์ ์ถ๊ฐํ ์ ์๋ค.
Visitor Pattern์ ์ ์ฉํ๊ธฐ ์ํ ๋น๋ ์
์ ๋ฆฌ์ปต๊ณผ ์ ์ ์ํ์ ํ๋ ์ผํ๋ชฐ ์ฌ์ฅ๋์ด ๋๋ค๊ณ ์๊ฐํด๋ณด์. ๋์น ์ฑ๊ฒ ์ง๋ง ์ด ์์ ์์ ๊ฐ์ฒด๋ ์ํ(์ ๋ฆฌ์ปต, ์ ์ ์ํ)์ด ๋ ๊ฒ์ด๊ณ , ๋ก์ง์ ์ํ ์ฃผ๋ฌธ์ด ๋ ๊ฒ์ด๋ค.
- ์ํ : ์ ๋ฆฌ์ปต, ์ ์ ์ํ
- ์ฃผ๋ฌธ : ํฌ์ฅ, ๋ฐฐ์ก, ํฌ์ธํธ ์ ๋ฆฝ(์ถ๊ฐ ๊ธฐ๋ฅ)
์ด์ ์ด ์์ ๋ฅผ ๊ตฌํํ๋ ๊ณผ์ ์์ ๋ช ๊ฐ์ง ๋ฌธ์ ๋ฅผ ์ง์ด๋ณด๊ณ , ์ด ๋ฌธ์ ๋ค์ ์ด๋ป๊ฒ Visitor ํจํด์ผ๋ก ํด๊ฒฐํ๋์ง ์์๋ณด์.
๋ฌธ์ 1. ์ ์ง ๋ณด์์ ์ด๋ ค์
- ์ผํ๋ชฐ์์ ํ๋งคํ๋ ์ํ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ๊ณ ์ด๋ฅผ ๊ตฌํํ๋ ์ ๋ฆฌ์ปต๊ณผ ์ ์ ์ํ ๊ตฌํ์ฒด๋ฅผ ๋ง๋ ๋ค.
/* ์ํ ์ธํฐํ์ด์ค */
public interface Product() {
public void pack();
public void deliver();
}
/* ์ ๋ฆฌ์ปต ๊ตฌํ์ฒด */
public class Glass implements Product {
// ํฌ์ฅ
@Override
public void pack() { System.out.println("๋ฝ๋ฝ์ด๋ก ์์ ํ๊ฒ ํฌ์ฅ"); }
// ๋ฐฐ์ก
@Override
public void deliver() {System.out.println("ํ ๋ฌ ๋์ ๋๊ธํ๊ฒ ๋ฐฐ์ก"); }
}
/* ์ ์ ์ํ ๊ตฌํ์ฒด */
public class FreshGrocery implements Product {
// ํฌ์ฅ
@Override
public void pack() { System.out.println("์์ด์คํฉ์ผ๋ก ์ ์ ํ๊ฒ ํฌ์ฅ"); }
// ๋ฐฐ์ก
@Override
public void deliver() {System.out.println("ํ๋ฃจ๋ง์ ํต์ผ๋ก ๋ฐฐ์ก"); }
}
[์คํ]
public static void main(String[] args) {
Product glass = new Glass();
Product freshGrocery = new FreshGrocery();
glass.pack();
glass.deliver();
freshGrocery.pack();
freshGrocery.deliver();
}
- ์์ ๋ฐฉ๋ฒ์ผ๋ก ๊ตฌํํ ๊ฒฝ์ฐ ๋ชจ๋ ๊ฐ์ฒด๋ง๋ค ๋ก์ง์ ์ํ ๋ฉ์๋๋ฅผ ์ ์ํด์ผํ๊ธฐ ๋๋ฌธ์ 1) ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ ์ด๋ ค์ธ ๋ฟ๋ง ์๋๋ผ 2) ํน์ ๊ฐ์ฒด์์ ๋ก์ง ๊ตฌํ์ ๋นผ๋จน๊ธฐ๋ ์ฝ๋ค.
- ๋ํ ๋ชจ๋ ๊ฐ์ฒด์ ๋ํด ๊ธฐ๋ฅ์ ์ํํ๊ฒ ํ๊ธฐ ์ํด์๋ ์์์์ฒ๋ผ main()์์ ๋ชจ๋ ๊ฐ์ฒด ๋ณ ๊ฐ ํจ์๋ฅผ ์ง์ ํธ์ถํด์ผํ๊ธฐ ๋๋ฌธ์ 3) iterator๋ฅผ ํตํ ๋ฐ๋ณต์ ์ธ ์ฒ๋ฆฌ๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
๋ฌธ์ 2. ๊ฐ์ฒด ๋ถ๊ธฐ์ ์ด๋ ค์ ๋ฐ ์ฝ๋ ์ค๋ณต
1๋ฒ ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ฐ์ฒด์ ๊ธฐ๋ฅ ๋ก์ง์ ๋ถ๋ฆฌํด๋ณด์.
- 1๋ฒ ์์ ์์ ์ํ ๊ฐ์ฒด๋ค์ ์ ์งํ๋, ๊ธฐ๋ฅ์ ์ํ ๋ฉ์๋๋ ์ ๊ฑฐํ๋ค.
- ์ฃผ๋ฌธ ์ธํฐํ์ด์ค๋ฅผ ์ ์ํ ๋ค, ์ด๋ฅผ ๊ตฌํํ ์ธ๋ถ ๊ธฐ๋ฅ ๊ตฌํ์ฒด๋ฅผ ์ ์ํ๋ค.
[์ํ ๊ฐ์ฒด]
/* ์ํ ์ธํฐํ์ด์ค */
public interface Product() { }
/* ์ ๋ฆฌ์ปต ๊ตฌํ์ฒด */
public class Glass implements Product { }
/* ์ ์ ์ํ ๊ตฌํ์ฒด */
public class FreshGrocery implements Product { }
[์ฃผ๋ฌธ ๊ธฐ๋ฅ]
/* ์ฃผ๋ฌธ ์ธํฐํ์ด์ค */
public interface Order {
public void pack(Product product);
public void deliver(Product product);
}
/* ์ฃผ๋ฌธ ๊ตฌํ์ฒด */
public class OrderImpl implements Order {
// ํฌ์ฅ
@Override
public void pack(Product product) {
if (product instanceof Glass) {
// ์ ๋ฆฌ์ปต ํฌ์ฅ
System.out.println("๋ฝ๋ฝ์ด๋ก ์์ ํ๊ฒ ํฌ์ฅ");
} else if (product instanceof FreshGrocery) {
// ์ ์ ์ํ ํฌ์ฅ
System.out.println("์์ด์คํฉ์ผ๋ก ์ ์ ํ๊ฒ ํฌ์ฅ");
}
}
// ๋ฐฐ์ก
@Override
public void deliver(Product product) {
if (product instanceof Glass) {
// ์ ๋ฆฌ์ปต ๋ฐฐ์ก
System.out.println("ํ ๋ฌ ๋์ ๋๊ธํ๊ฒ ๋ฐฐ์ก");
} else if (product instanceof FreshGrocery) {
// ์ ์ ์ํ ๋ฒ ์ก
System.out.println("ํ๋ฃจ๋ง์ ํต์ผ๋ก ๋ฐฐ์ก");
}
}
}
[์คํ]
public static void main(String[] args) {
Product glass = new Glass();
Product freshGrocery = new FreshGrocery();
Order order = new OrderImpl();
order.pack(glass);
order.pack(freshGrocery);
order.deliver(glass);
order.deliver(freshGrocery);
}
- ์ ์ฝ๋๋ 1๋ฒ์ ๋ฌธ์ ์ ์ธ ๋ฐ๋ณต์ ์ธ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ก์ง๋ง ์ฌ์ ํ ๋ฌธ์ ๊ฐ ๋จ์์๋ค. ํนํ
if (product instanceof Glass)
๋ถ๋ถ์ผ๋ก ๋ถ๊ธฐํ๋ ๋ถ๋ถ์ด ์ฑ์ ์์ฐฌ๋ค. - ์ด๋ ๊ฒ ๊ฐ์ฒด๋ฅผ ๋ถ๊ธฐํ ๊ฒฝ์ฐ 1) ํน์ ๊ฐ์ฒด์ ๋ํ ๋ถ๊ธฐ๋ฅผ ๋นผ๋จน์ ์๋ ์์ ๋ฟ๋ง ์๋๋ผ, ๋น์ทํ ๊ตฌ์กฐ๊ฐ ๋ฐ๋ณต๋๋ ์ฝ๋ ์ค๋ณต์ด ๋ฐ์ํ๋ค.
- ์ฆ, 1๋ฒ์ ๋ฌธ์ ๋ฅผ ๊ฑฐ์ ํด๊ฒฐํ์ง ๋ชปํ ๊ฒฉ์ด๋ค.
๋ฌธ์ 3. Single Dispatch(Dynamic Dispatch) ๋ฌธ์
๐ฏ Dispatch๋?
- Dispatch๋ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ ๋ฐฉ์์ ๋งํ๋ค.
- ์๋ฐ๋ ๋ฐํ์ ์์ ์ด๋ค ๋ฉ์๋๋ฅผ ํธ์ถํ ์ง ๊ฒฐ์ ํ๋, ์ฆ ๋ฐํ์ ์์ ์์ฑ๋๋ ์ธ์คํด์ค๋ฅผ ๋์ ์ผ๋ก ํ์ ์ฒดํฌ ํ๋
dynamic dispatch
๋ง์ ์ง์ํ๋ค.(single dispatch)
์์
- 2๋ฒ ์์ ์ ์ํ ๊ฐ์ฒด์ ์ฃผ๋ฌธ ํด๋์ค๋ฅผ ์ ์งํ๋, ์ฃผ๋ฌธ ํด๋์ค์์ ๊ฐ ์ํ ํ์ ๋ณ ๋ฉ์๋๋ฅผ ์์ฑํ๋ค.
[์ฃผ๋ฌธ ๊ธฐ๋ฅ]
/* ์ฃผ๋ฌธ ์ธํฐํ์ด์ค */
public interface Order {
public void pack(Glass glass);
public void pack(FreshGrocery freshGrocery);
public void deliver(Glass glass);
public void deliver(FreshGrocery freshGrocery);
}
/* ์ฃผ๋ฌธ ๊ตฌํ์ฒด */
public class OrderImpl implements Order {
// ์ ๋ฆฌ์ปต ํฌ์ฅ
@Override
public void pack(Glass glass) { System.out.println("๋ฝ๋ฝ์ด๋ก ์์ ํ๊ฒ ํฌ์ฅ"); }
// ์ ์ ์ํ ํฌ์ฅ
@Override
public void pack(FreshGrocery freshGrocery) { System.out.println("์์ด์คํฉ์ผ๋ก ์ ์ ํ๊ฒ ํฌ์ฅ"); }
// ์ ๋ฆฌ์ปต ๋ฐฐ์ก
@Override
public void deliver(Glass glass) { System.out.println("ํ ๋ฌ ๋์ ๋๊ธํ๊ฒ ๋ฐฐ์ก"); }
// ์ ์ ์ํ ๋ฐฐ์ก
@Override
public void deliver(FreshGrocery freshGrocery) { System.out.println("ํ๋ฃจ๋ง์ ํต์ผ๋ก ๋ฐฐ์ก"); }
}
[์คํ]
public static void main(String[] args) {
Product glass = new Glass();
Product freshGrocery = new FreshGrocery();
Order order = new OrderImpl();
order.pack(glass);
order.pack(freshGrocery);
order.deliver(glass);
order.deliver(freshGrocery);
}
- ์ด๋ฒ ์์ ๋ 2๋ฒ ์์ ์ ์คํ ๋ถ๋ถ์ธ main() ๋ถ๋ถ์ด ๋์ผํ๋ค. ์ธ๋ป๋ณด๋ฉด ๊ฐ๋ฅํด ๋ณด์ผ์ง๋ผ๋ ์ด๋ฒ์๋
์ปดํ์ผ ์๋ฌ
๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค. - OrderImpl ํด๋์ค ๋ด๋ถ์ pack() ๋ฉ์๋์ deliver() ๋ฉ์๋๋ ๊ฐ๊ฐ ์๋ก ๋ค๋ฅธ ๋งค๊ฐ๋ณ์ ํ์ (Glass, FreshGrocery)์ผ๋ก ์ ์ํ์ฌ ์ค๋ฒ๋ก๋ฉํ๊ณ ์๋ค.
- ํ์ง๋ง ์คํ ๋ถ๋ถ์์๋ glass์ freshGrocery ์ธ์คํด์ค ๋ชจ๋ Product ํ์ ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ๊ณ ์๋ค. ๋ฐ๋ผ์ ์ค์ ๋ก๋ Glass ํ์ ๊ณผ FreshGrocery ํ์ ์ ์ธ์คํด์ค์ผ์ง๋ผ๋, Dynamic Dispatch ํน์ฑ ์ ์ปดํ์ผ ์ Glass ํ์ ๊ณผ FreshGrocery ํ์ ์ผ๋ก ์ธ์๋ ์ ์๋ค.
- ๋ ์์ ํ์ ์ ๋ ํฐ ํ์ ์ ๊ฐ์ฒด๋ฅผ ๋ฃ์ ์ ์๋ค!!
- ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์๊ณ glass์ freshGrocery ์ธ์คํด์ค๋ฅผ Product ํ์ ์ด ์๋ Glass ํ์ ๊ณผ FreshGrocery ํ์ ์ผ๋ก ์์ฑํ๊ฒ ๋๋ค๋ฉด ์ด๋ ๋ ์ด์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ์๋ฏธ๊ฐ ์๋ ์ฝ๋๊ฐ ๋์ด๋ฒ๋ฆฐ๋ค.
Visitor Pattern์ ์ด์ฉํ ํด๊ฒฐ ๋ฐฉ์
์ด์ ์์ ๋ฌธ์ ์ ๋ค์ Visitor Pattern์ ์ด์ฉํด ํด๊ฒฐํด๋ณด์.
- 1๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ฐ์ฒด์ ๋ก์ง์ ๋ถ๋ฆฌํ ๊ฒ์ด๋ค.
- ๋ํ 2๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๊ฐ ๊ฐ์ฒด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ํ๋ ๊ธฐ๋ฅ ๋ฉ์๋๋ฅผ ๊ฐ๊ฐ ์ ์ํ๋ค.
- ๋ง์ง๋ง์ผ๋ก Double Dispatch๋ฅผ ๊ตฌํํ์ฌ 3๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค!
[์ํ ๊ฐ์ฒด]
/* ์ํ ์ธํฐํ์ด์ค */
public interface Product() {
public void order(Order order);
}
/* ์ ๋ฆฌ์ปต ๊ตฌํ์ฒด */
public class Glass implements Product {
@Override
public void order(Order order) {
order.placeOrder(this);
}
}
/* ์ ์ ์ํ ๊ตฌํ์ฒด */
public class FreshGrocery implements Product {
@Override
public void order(Order order) {
order.placeOrder(this);
}
}
[์ฃผ๋ฌธ ๊ธฐ๋ฅ]
/* ์ฃผ๋ฌธ ์ธํฐํ์ด์ค */
public interface Order {
public void placeOrder(Glass glass);
public void placeOrder(FreshGrocery freshGrocery);
}
/* ํฌ์ฅ ์ฃผ๋ฌธ ๊ตฌํ์ฒด */
public class PackOrder implements Order {
// ์ ๋ฆฌ์ปต ํฌ์ฅ
@Override
public void placeOrder(Glass glass) { System.out.println("๋ฝ๋ฝ์ด๋ก ์์ ํ๊ฒ ํฌ์ฅ"); }
// ์ ์ ์ํ ํฌ์ฅ
@Override
public void placeOrder(FreshGrocery freshGrocery) { System.out.println("์์ด์คํฉ์ผ๋ก ์ ์ ํ๊ฒ ํฌ์ฅ"); }
}
/* ๋ฐฐ์ก ์ฃผ๋ฌธ ๊ตฌํ์ฒด */
public class DeliverOrder implements Order {
// ์ ๋ฆฌ์ปต ๋ฐฐ์ก
@Override
public void placeOrder(Glass glass) { System.out.println("ํ ๋ฌ ๋์ ๋๊ธํ๊ฒ ๋ฐฐ์ก"); }
// ์ ์ ์ํ ๋ฐฐ์ก
@Override
public void placeOrder(FreshGrocery freshGrocery) { System.out.println("ํ๋ฃจ๋ง์ ํต์ผ๋ก ๋ฐฐ์ก"); }
}
/* ํฌ์ธํธ ์ ๋ฆฝ ์ฃผ๋ฌธ ๊ตฌํ์ฒด */
public class pointSaveOrder implements Order {
// ์ ๋ฆฌ์ปต ํฌ์ธํธ ์ ๋ฆฝ
@Override
public void placeOrder(Glass glass) { System.out.println("๊ตฌ๋งค ๊ธ์ก์ 10% ์ ๋ฆฝ"); }
// ์ ์ ์ํ ํฌ์ธํธ ์ ๋ฆฝ
@Override
public void placeOrder(FreshGrocery freshGrocery) { System.out.println("๊ตฌ๋งค ๊ธ์ก์ 5% ์ ๋ฆฝ"); }
}
[์คํ]
public static void main(String[] args) {
Product glass = new Glass();
Product freshGrocery = new FreshGrocery();
Order packOrder = new PackOrder();
Order deliverOrder = new DeliverOrder();
glass.order(packOrder);
glass.order(deliverOrder);
freshGrocery.order(packOrder);
freshGrocery.order(deliverOrder);
}
Visitor ํจํด์ ์ ์ฉํ ์ดํ ๋ฌ๋ผ์ง ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ํ ๊ฐ์ฒด ๋ด์์ ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ๊ตฌํํ์ง ์์๋ ๋๋ค.
- ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ํด๋์ค๋ก ๋นผ๋ธ ๋ค, ๊ฐ ์ํ ๊ฐ์ฒด ํ์ ๋ณ ๋ณ๋์ ๋ฉ์๋๋ฅผ ์ ์ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๊ตฌํ์ ๋นผ๋จน์ ์ํ์ด ์ ๋ค.
- ๊ฐ ์ํ ํ์
๊ฐ์ฒด์์ ๊ธฐ๋ฅ ํจ์๋ฅผ ํธ์ถํ์ฌ ์ฌ์ฉํ๊ณ ์๊ธฐ ๋๋ฌธ์
single dispatch
๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ค. (๋ ํฐ ํ์ ์์ ๋ ์์ ํ์ ์ ๊ฐ์ฒด๋ฅผ ๋ฐ๊ณ ์๊ธฐ ๋๋ฌธ์) - ์๋ก์ด ์ฃผ๋ฌธ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ธฐ๊ฐ ์ฝ๋ค! ๊ฐ์ฒด์์๋ ๋ณ๊ฒฝ ์์ด ์ค์ง ์ฃผ๋ฌธ ํด๋์ค๋ง ์ถ๊ฐํ๋ฉด ๋๋ค.
์ถ๊ฐ์ ์ผ๋ก Visitor Pattern์์ ํํ ๋งํ๋ Visitor, Element์ ์ญํ ์ ๋ค์๊ณผ ๊ฐ์ด ๋งค์นญ๋ ์ ์๋ค.
- Visitor : ๊ธฐ๋ฅ์ด๋ ๋ก์ง์ ์ํ ์ธํฐํ์ด์ค ex) Order ์ธํฐํ์ด์ค
- ConcreteVisitor : ๊ธฐ๋ฅ์ด๋ ๋ก์ง ๊ตฌํ์ฒด ex) PackOrder ํด๋์ค, DeliverOrder ํด๋์ค, pointSaveOrder ํด๋์ค
- visit(Element) : ๊ฐ์ฒด์์ ํธ์ถ๋์ด ์ฌ์ฉํ๊ธฐ ์ํด ๊ธฐ๋ฅ ํด๋์ค๊ฐ ๊ณตํต์ ์ผ๋ก ๊ตฌํํด์ผ ํ ๋ฉ์๋ ex) placeOrder()
- Element : ๊ธฐ๋ฅ์ด๋ ๋ก์ง์ ์ฌ์ฉํ ๊ฐ์ฒด ์ธํฐํ์ด์ค ex) Product ์ธํฐํ์ด์ค
- ConcreteElement : ๊ฐ์ฒด ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด ex) Glass ํด๋์ค, FreshGrocery ํด๋์ค
- accept(Visitor) : ๊ธฐ๋ฅ ํด๋์ค ๋ด์ visit ๋ฉ์๋๋ฅผ ํธ์ถํ๊ธฐ ์ํด ๋ชจ๋ ๊ฐ์ฒด๊ฐ ๊ตฌํํด์ผ ํ ๋ฉ์๋ ex) order()