개발/Spring

[Spring] 템플릿 메소드 패턴과 팩토리 메소드 패턴

hojak99 2017. 8. 16. 15:28

학교에서 빌린 토비의 스프링 책을 이제는 더 이상 볼 수 없기에 책을 못 보던 중 회사에 엄청 옛날에 나온 토비 책이 있어서 보는데 템플릿 메소드 패턴과 팩토리 메소드 패턴이 헷갈렸다.  그래서 검색해보았는데 다들 어렵게 설명하고 해서 조금 이해하기 힘들어서 정리해보려고 한다.


설명이 정확하지 않을 확률이 좀 더 높다. 




■ 템플릿 메소드 패턴

간단하게 템플릿 메소드 패턴에 대해 이야기 하자면 다음과 같다.

슈퍼 클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 이런 메소드를 필요에 맞게 구현해 사용하도록 하는 방법


좀 더 쉽게 말하면 다음과 같다.

슈퍼 클래스에 기본적인 메소드가 정의되어 있고 세부적인 메소드는 추상 메소드로 두워 서브 클래스에서 구현해 사용하는 방법



팩토리 메소드 패턴


간단하게 팩토리 메소드 패턴에 대해 이야기 하자면 다음과 같다.

서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것









솔직히 글을 작성하는데도 저 설명이 이 설명이고 이 설명이 저 설명인 것 같이 헷갈린다.


코드로 확인해보면 좀 더 이해가 쉬울 것 같다.  다음의 로직으로 템플릿 메소드 패턴을 설명하도록 하겠다.


컴퓨터를 킨다.


인터넷 익스플로어를 킨다.

검색한다.

컴퓨터를 종료한다.


========================================================


컴퓨터를 킨다.


크롬을 킨다.

검색한다.

컴퓨터를 종료한다.



■ 템플릿 메소드 패턴


package com.kjh.hojak.controller;

public class Main {
	public static void main(String[] args) {
		Chrome chrome = new Chrome();
		chrome.working();
		
		System.out.println();
		
		Ie ie = new Ie();
		ie.working();
	}

}

class Chrome {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		System.out.println("크롬을 킨다.");
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
}

class Ie {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		System.out.println("인터넷 익스플로어를 킨다.");
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
}


Chrome 클래스와 Ie 클래스를 살펴보면 working() 메소드에 "크롬/인터넷 익스플로어를 킨다" 를 제외한 코드가 같다는 것을 볼 수 있다. 


이러한 코드들을 좀 더 객체지향적(?)인 상속을 이용해 코드를 바꿔보자.



package com.kjh.hojak.controller;

public class Main {
	public static void main(String[] args) {
		Chrome chrome = new Chrome();
		chrome.working();
		
		System.out.println();
		
		Ie ie = new Ie();
		ie.working();
	}

}

abstract class Work {
	public abstract void working();
}

class Chrome extends Work {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		System.out.println("크롬을 킨다.");
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
}

class Ie extends Work {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		System.out.println("인터넷 익스플로어를 킨다.");
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
}


다음과 같이 상속을 이용해 추상 클래스인 Work 클래스에 working 메소드를 각각의 클래스에서 구현해 사용했지만 아직 뭔가 부족한 코드이다. 중복되는 코드들을 없애보자.


package com.kjh.hojak.controller;

public class Main {
	public static void main(String[] args) {
		Chrome chrome = new Chrome();
		chrome.working();
		
		System.out.println();
		
		Ie ie = new Ie();
		ie.working();
	}

}

abstract class Work {
	public abstract void working();
}

class Chrome extends Work {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		browser();
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
	
	public void browser(){
		System.out.println("크롬을 킨다.");
	}
}

class Ie extends Work {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		browser();
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
	
	public void browser(){
		System.out.println("인터넷 익스플로어를 킨다.");
	}
}


뭔가 슬슬 보이기 시작할 때이다. 각각의 Chrome 클래스와 Ie 클래스의 working 메소드의 코드가 같다는 것을 알 수가 있다. 그렇다면 working 코드를 부모 클래스인 Work 클래스로 옮겨보자.



package com.kjh.hojak.controller;

public class Main {
	public static void main(String[] args) {
		Chrome chrome = new Chrome();
		chrome.working();
		
		System.out.println();
		
		Ie ie = new Ie();
		ie.working();
	}

}

abstract class Work {
	public void working(){
		System.out.println("컴퓨터 킨다.");
		browser();
		System.out.println("검색을 한다.");
		System.out.println("컴퓨터를 끈다.");
	}
	
	public abstract void browser();
}

class Chrome extends Work {

	public void browser(){
		System.out.println("크롬을 킨다.");
	}
	
}

class Ie extends Work {
	
	public void browser(){
		System.out.println("인터넷 익스플로어를 킨다.");
	}
	
}


이렇게 객체지향적인 코드가 완성이 되었다. 이런 식으로 부모 클래스에서 기본적인 로직의 흐름을 짜고, 기능의 일부를 추상 메소드나 오버라이딩이 가능한 protected 메소드 등으로 만든 뒤 서브 클래스에서 구현해 사용하는 방법이 바로 템플릿 메소드 패턴이다.







■ 팩토리 메소드 패턴

팩토리 메소드 패턴에 대해서는 유저의 정보를 DB 에서 가져오는 코드로 설명을 하겠다.  다시 말하길 팩토리 메소드 패턴은 서브클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것을 말한다.


abstract class UserDao {
	public void add(User user) {
		Connection c = getConnection();
	}
	
	public User get(String id) {
		Connection c = getConnection();
	}
	
	public abstract Connection getConnection();
}


class OracleUserDao extends UserDao{
	public Connection getConnection(){
		// 오라클 connection 생성코드
	}
}

class MySqlUserDao extends UserDao{
	public Connection getConnection(){
		// MySql connection 생성코드
	}
}



반응형