Yeongjun's Wicksome documents ๐ŸŒฑ

Template Method Pattern

Topics: design pattern, java

์˜๋„

์—ฐ์‚ฐoperation์— ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๋ผˆ๋Œ€๋งŒ ์ •์˜ํ•˜๊ณ , ๊ตฌ์ฒด์  ์ฒ˜๋ฆฌ๋Š” ์„œ๋ธŒํด๋ž˜์Šค๋กœ ๋ฏธ๋ฃฌ๋‹ค. ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌ์กฐ๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋‹จ๊ณ„์ฒ˜๋ฆฌ๋งŒ ์„œ๋ธŒํด๋ž˜์Šค๋Š”์—์„œ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

๊ตฌ์กฐ

Template Method Pattern

ํ™œ์šฉ์„ฑ

  • ์–ด๋–ค ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด๋ฃจ๋Š” ๋ถ€๋ถ„ ์ค‘ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ํ•œ ๋ฒˆ ์ •์˜ํ•ด ๋†“๊ณ  ๋‹ค์–‘ํ•ด์งˆ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์€ ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‚จ๊ฒจ๋‘๊ณ ์ž ํ•  ๋•Œ
  • ์„œ๋ธŒํด๋ž˜์Šค ์‚ฌ์ด์˜ ๊ณตํ†ต์ ์ธ ํ–‰๋™์„ ์ถ”์ถœํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ณตํ†ต ํด๋ž˜์Šค์— ๋ชฐ์•„๋‘ ์œผ๋กœ์จ ์ฝ”๋“œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ณ  ์‹ถ์„ ๋•Œ. ์ด๊ฒƒ์€ Opdyke์™€ Johnson์ด ์„ค๋ช…ํ•œ[OJ93][^1] "refactoring to generalize"์˜ ์ข‹์€ ์˜ˆ์ด๋‹ค. ๋จผ์ € ๊ธฐ์กด์ฝ”๋“œ์—์„œ ์ฐจ์ด์ ์„ ์ฐพ๊ณ  ์ด๋ฅผ ์ƒˆ๋กœ์šด ์—ฐ์‚ฐ์œผ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ ๋‹ฌ๋ผ์ง„ ์ฝ”๋“œ ๋ถ€๋ถ„์„ ์ƒˆ๋กœ์šด ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•˜๋Š” ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋กœ ๋Œ€์ฒดํ•œ๋‹ค.
  • ์„œ๋ธŒํด๋ž˜์Šค์˜ ํ™•์žฅ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๊ฐ€ ์–ด๋–ค ํŠน์ •ํ•œ ์‹œ์ ์— "hook" ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•˜๋„๋ก ์ •์˜ํ•จ์œผ๋กœ์จ, ๊ทธ ํŠน์ • ์‹œ์ ์—์„œ๋งŒ ํ™•์žฅ๋˜๋„๋ก ํ•œ๋‹ค.

๊ฒฐ๊ณผ

  • ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•œ ๊ธฐ๋ณธ ๊ธฐ์ˆ ์ด๋‹ค(ํŠนํžˆ ํด๋ผ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌํ˜„ ์‹œ ์ค‘์š”).
  • ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” IoC(Inversion of Control, ์ œ์–ด ์—ญ์ „) ๊ตฌ์กฐ๋ฅผ ์ด๋Œ์–ด ๋‚ธ๋‹ค. ์ฆ‰, ๋ถ€๋ชจ ํด๋ž˜์Šค๋Š” ์„œ๋ธŒํด๋ž˜์Šค์— ์ •์˜๋œ ์—ฐ์‚ฐ์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์˜ ํ˜ธ์ถœ์€ ์•ˆ ๋œ๋‹ค. {% blockquote ํ• ๋ฆฌ์šฐ๋“œ ์›์น™(Hollywood principle) %} Don't call us, we'll call you. {% endblockquote %}
  • ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์—ฐ์‚ฐ ์ค‘ ํ•˜๋‚˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

    • ๊ตฌ์ฒด ์—ฐ์‚ฐ
    • AbstractClass ๊ตฌ์ฒด ์—ฐ์‚ฐ
    • ๊ธฐ๋ณธ ์—ฐ์‚ฐ
    • factory method
    • hook operation: ํ•„์š”ํ•˜๋‹ค๋ฉด ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ํ™œ์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ํ–‰๋™์„ ์ œ๊ณตํ•˜๋Š” ์—ฐ์‚ฐ. ๊ธฐ๋ณธ์ ์œผ๋กœ ์•„๋ฌด ๋‚ด์šฉ๋„ ์ •์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ตฌํ˜„

  • ์ ‘๊ทผ์ œ์–ด์ž๋ฅผ ์ด์šฉํ•œ๋‹ค. - ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ์—์„œ ํ˜ธ์ถœํ•˜๋Š” ๊ธฐ๋ณธ ์—ฐ์‚ฐ๋“ค์„ protected๋กœ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ด ์—ฐ์‚ฐ๋“ค์€ ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” ์žฌ์ •์˜ํ•˜๋ฉด ์•ˆ๋˜๋ฏ€๋กœ ๋งด๋ฒ„ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ ๋‹ค(final๋กœ ์ •์˜ํ•˜๋ฉด ์žฌ์ •์˜ ๋ถˆ๊ฐ€๋Šฅ).
  • ๊ธฐ๋ณธ ์—ฐ์‚ฐ์˜ ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•œ๋‹ค. - ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ์ค‘์š”ํ•œ ๋ชฉํ‘œ ์ค‘ ํ•˜๋‚˜๋Š” ์„œ๋ธŒํด๋ž˜์Šค๊ฐ€ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด์•ผ ํ•˜๋Š” ์—ฐ์‚ฐ์˜ ์ˆ˜๋ฅผ ์ตœ์†Œํ™”ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์žฌ์ •์˜ํ•ด์•ผ ํ•˜๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์‚ฌ์šฉ์ž๋Š” ๋ถˆํŽธํ•ด์ง„๋‹ค.
  • ๋„ค์ด๋ฐ ๊ทœ์น™์„ ๋งŒ๋“ ๋‹ค. - ์žฌ์ •์˜ ์—ฐ์‚ฐ์— ์ ‘๋‘์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์‹๋ณ„์ด ์ž˜๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋งคํ‚จํ† ์‹œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ์˜ MapAPPํ”„๋ ˆ์ž„์›Œํฌ[App89][^2]์˜ ๋ชจ๋“  ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” Do-๋กœ ์‹œ์ž‘ํ•œ๋‹ค. DoCreateDocument, DoRead

์˜ˆ์ œ

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

์ด๋Ÿฐ ๊ฒฝ์šฐ์— openNewDocument() ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Application.java๋Š” ํ•ญ์ƒ ํ™•์ธํ•ด์•ผํ•  ์—ฐ์‚ฐ(ํŒŒ์ผ ์กด์žฌ ํ™•์ธ, ๊ถŒํ•œ ํ™•์ธ)์„ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋กœ ์ •์˜ํ•˜๊ณ  ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค. Application์—์„œ beforeCreateDocument()๋Š” hook ์—ฐ์‚ฐ์œผ๋กœ ํ•„์š”์—๋”ฐ๋ผ ํ™•์žฅํ•ด์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ

์ถ”์ƒ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ผ๋ถ€๋ฅผ ์ •์˜ํ•จ์œผ๋กœ์จ, ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ๋Š” ๊ฐ ๋‹จ๊ณ„์˜ ์ˆœ์„œ๋Š” ๊ณ ์ •ํ•˜๋˜ ๊ฐ๊ฐ์˜ ์„œ๋ธŒํด๋ž˜์Šค๋Š” ํ•„์š”์— ๋”ฐ๋ผ ์ด๋“ค ๋‹จ๊ณ„์˜ ์ฒ˜๋ฆฌ๋ฅผ ๋‹ค์–‘ํ™”์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

Application.java(AbstractClass)

public abstract class Application {
	public Document newDcument() { return createDocument(); }
	public abstract Document createDocument(); // factory method

	// template method
	final public Document openNewDocument(String fileName) {
		if (!existDocument(fileName)) {
			throw new IllegalStateException("The file doesn't exist: " + fileName);
		}

		if (!canOpenDocument(fileName)) {
			throw new IllegalStateException("can't open the document: " + fileName);
		}

		beforeCreateDocument(); // hook ์—ฐ์‚ฐ
		Document document = createDocument(); // template method์—์„œ factory method๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
		document.setFileName(fileName);
		return document;
	}

	protected abstract boolean existDocument(String fileName);
	protected abstract boolean canOpenDocument(String fileName);

	protected void beforeCreateDocument() {} // hook: ๊ธฐ๋ณธ์ ์œผ๋กœ ์•„๋ฌด ๋‚ด์šฉ๋„ ์ •์˜ํ•˜์ง€ ์•Š๋Š”๋‹ค.
}

MyApplication.java(ConcreteClass)

public class MyApplication extends Application {
	private static final String BASE_PATH = "/local/path/base";

	@Override
	public void beforeCreateDocument() { System.out.println("create document"); }

	@Override
	public Document createDocument() { return new WordDocument(); }

	@Override
	protected boolean existDocument(String fileName) {
		return (new File(BASE_PATH + fileName)).exists();
	}

    ...
}

์•„๋ž˜ ์ฑ…๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌ/๊ธฐ๋กํ•œ ํฌ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ฑ…์„ ์ฐธ๊ณ ํ•˜์‹œ๊ธฐ ๋ฐ”๋ผ๋ฉฐ, ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์—ฐ๋ฝ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

  • [GOF{kr}:419] - ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ
  • GoF, ๊น€์ •์•„(์˜ฎ๊ธด์ด), Design Patterns, ๊ฐœ์ •ํŒ, ํ”„๋กœํ…๋ฏธ๋””์–ด, 2015.

  1. William F. Opdyke and Ralph E. Johnson. Creating abstract superclasses by refactoring. In Proceedings of the 21st Annual Computer Science Conference (ACM CSC '93), pages 66โ€“73, Indianapolis, IN, February 1993.

    โ†ฉ
  2. Addison-Wesley, Reading, MA. NEXTSTEP General Reference: Release 3, Volumes 1 and 2, 1994.

    โ†ฉ

Comments

Previous PostFactory Method Pattern
Next Post์ดํŽ™ํ‹ฐ๋ธŒ์ž๋ฐ” 5์žฅ. ์ œ๋„ค๋ฆญ(1)