정의

  • 서로 다른 클래스들의 알고리즘이 공통될 때(상세 기능이 아닌 일반적인 관점에서) 공통된 알고리즘을 슈퍼클래스에서 정의하고 일부 다른부분은 추상 메소드로 정의하여 서브클래스에서 구현하는 패턴

템플릿 메소드 패턴의 특징

  • 코드의 재사용에 크게 도움된다.
  • 클래스간의 의존성을 낮춰준다.
  • 프레임워크를 만들때 자주 사용되는 패턴이다.
  • 변경이 일어나지 않는 부분은 슈퍼 클래스에서 final로 지정하여 오버라이드하지 못하게 막는다

템플릿 메소드 디자인 원칙(책에서는 헐리우드 원칙이라 나옴)

  • 저수준 구성요소가 고수준의 구성요소를 직접 호출할 수 없다.(고수준의 구성요소에서 호출하기전에 저수준 구성요소는 대기한다.)
  • 클래스의 주요 기능은 고수준 구성요소에서 장악하고 구현이 필요한 기능만 저수준 클래스를 호출한다.
  • 클래스의 구성요소들의 사용은 고수준 구성요소(템플릿을 가진 슈퍼클래스를 말하는듯)에서 결정한다.
  • 저수준 구성요소(템플릿에서 추상메소드로 정의한 메소드를 상세구현한 자식 클래스)는 고수준 구성 요소를 직접 호출할수 없다.
  • 이 원칙이 위반되면 클래스간의 의존도가 매우 높아진다.

서로 다른 종류의 DB 조회 적용 예제

  • 오라클/mysql/mssql….등등 하나의 어플리케이션에서 여러대의 DB에 select쿼리를 사용 한다고 가정.
  • 템플릿 메소드 패턴을 사용하지 않고 가져올 경우 아래의 코드를 각 클래스마다 사용해야함
public class OracleSelect {
	public void getSelect(){
		try{
			System.out.println("Oracle Driver Loading");
		}catch(Exception e){
			System.out.println("Oracle Driver Loading Exception");
		}

		try{
			System.out.println("Oracle getConnection");
			System.out.println("Oracle createStatement");
			System.out.println("Oracle executeQuery");
		}catch(Exception e){
			System.out.println("Oracle Exception");
		}finally{
			System.out.println("Oracle Resource Close");
		}
	}
}

템플릿 메소드의 적용

  • 각 DB연결후 쿼리를 가져오는 부분에서 사용되는 기능들을 일반적인 관점으로 공통화 시킨다.
    1. 오라클 드라이버를 로딩한다./My-sql 드라이버를 로딩한다.(x) -> DB드라이버를 로딩한다.
    2. 오라클 커넥션을 가져온다./My-sql 커넥션을 가져온다.(x) -> 커넥션을 가져온다.
    3. 오라클 statement을 생성한다./My-sql statement을 생성한다.(x) -> statement을 생성한다.
    4. 오라클에 select 쿼리를 날린다./My-sql에 select 쿼리를 날린다.(x) -> select 쿼리를 날린다.
    5. 오라클에 사용된 리소스를 close한다./My-sql에 사용된 리소스를 close한다.(x) -> 리소스를 close한다.
  • 공통화 시킨 기능을 토대로 템플릿으로 사용될 기능에서 변경이 안되는 부분, 변경될 부분을 분리하여 변경이 안되는 부분은 final로 변경되는 부분은 추상메소드로 기능을 정의한다.
  • 적용 예
//템플릿으로 사용될 부분
public abstract class DBSelectTemplate {
final void getSelect(String dbName,String query){
	try{
		driverLoading(dbName);
	}catch(Exception e){
		System.out.println(dbName + " Driver Loading Exception");
	}

	try{
		getConnection(dbName);
		createStatement(dbName);
		executeQuery(query);
	}catch(Exception e){
		System.out.println(dbName + " Exception");
	}finally{
		resourceClose(dbName);
	}
}

//1.DB드라이버를 로딩한다.
final void driverLoading(String dbName){
	System.out.println(dbName + " Driver Loading");
}

//2.커넥션을 가져온다.
final void getConnection(String dbName){
	System.out.println(dbName + " getConnection");
}
//3.statement을 생성한다.
final void createStatement(String dbName){
	System.out.println(dbName + " createStatement");
}
//4.select 쿼리를 날린다.
abstract void executeQuery(String query);

//5.리소스를 close한다.
final void resourceClose(String dbName){
	System.out.println(dbName + " Resource Close");
}
}
public class MysqlSelectUseTemplate extends DBSelectTemplate{

	@Override
	void executeQuery(String query) {
		// TODO Auto-generated method stub
		System.out.println("Mysql ==> " + query);
	}

}

결과

  • 공통된 부분을 분리하여 적용함으로써 코드의 재사용율이 높아졌다.

템플릿 메소드가 사용된곳을 생각해보자

  • 샘플소스확인
  • 실전 패턴 적용이 교재에 나온 내용과 완전히 일치할 수 없다. 주어진 상황과 제약 조건에 맞추어 적용할 수 있어야한다. ex)Arrays.sort()