팩토리 메소드 패턴은 Super Class에 알려지지 않은 구체 클래스를 생성하는 패턴이며, 자식 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.
즉, 객체 생성 처리를 서브 클래스로 분리 해 처리하도록 캡슐화하는 패턴 으로 객체의 생성 코드를 별도의 클래스/메서드로 분리함으로써 객체 생성의 변화에 대비하는 데 유용하다.
주로 인터페이스 타입으로 오브젝트를 반환하므로 Super Class에서는 Sub Class에서 정확히 어떤 클래스의 오브젝트를 만들어 반환할지 알지 못한다.
public interface Shape{
abstract void draw();
}
public class Star extends Shape{
@Override
public void draw(){
System.out.println("별 그리기");
}
}
public class Square extends Shape{
@Override
public void draw(){
System.out.println("네모 그리기");
}
}
public class ShapeFactory{
public Shape getShape(String shapeType){
if(StringUtils.isEmpty(shapeType)){
return null;
}
if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}else if(shapeType.equalsIgnoreCase("STAR")){
return new Star();
}
return null;
}
}
public FactoryPatternTest{
public static void main(String[] args){
ShapeFactory shapeFactory = new ShapeFactory();
Shape shape1 = shapeFactory.getShape("STAR");
shape1.draw();
Shape shape2 = shapeFactory.getShape("SQUARE");
shape2.draw();
}
}
즉, 서브 클래스에서 오브젝트 생성 방법 클래스를 결정할 수 있도록 미리 정의해둔 메소드를 팩토리 메소드라고 하며, 이 방식을 통해 오브젝트를 생성하는 방법을 팩토리 메소드 패턴이라고 한다.
Factory Method Pattern을 왜 사용할까?
팩토리 메소드 패턴을 사용하는 이유는 클래스간의 결합도를 낮추기 위한것입니다. 결합도라는 것은 간단히 말해 클래스의 변경점이 생겼을 때 얼마나 다른 클래스에도 영향을 주는가입니다. 팩토리 메소드 패턴을 사용하는 경우 직접 객체를 생성해 사용하는 것을 방지하고 서브 클래스에 위임함으로써 보다 효율적인 코드 제어를 할 수 있고 의존성을 제거합니다. 결과적으로 결합도 또한 낮출 수 있습니다.
예제
Sub Class의 getConnection()을 통해 만들어진 Connection 종류가 달라질 수 있게 하는 것을 목적으로 하는 팩토리 메소드 패턴의 예시이다.
package springbook.user.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import springbook.user.domain.User;
public abstract class UserDao {
public void add(User user) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c.prepareStatement(
"insert into users(id, name, password) values(?,?,?)");
ps.setString(1, user.getId());
ps.setString(2, user.getName());
ps.setString(3, user.getPassword());
ps.executeUpdate();
ps.close();
c.close();
}
public User get(String id) throws ClassNotFoundException, SQLException {
Connection c = getConnection();
PreparedStatement ps = c
.prepareStatement("select * from users where id = ?");
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
rs.next();
User user = new User();
user.setId(rs.getString("id"));
user.setName(rs.getString("name"));
user.setPassword(rs.getString("password"));
rs.close();
ps.close();
c.close();
return user;
}
abstract protected Connection getConnection() throws ClassNotFoundException, SQLException ;
}
public static void main(String[] args) throws ClassNotFoundException, SQLException {
UserDao dao = new NUserDao();
User user = new User();
user.setId("admin");
user.setName("test1");
user.setPassword("admintest");
dao.add(user);
System.out.println(user.getId() + " 등록 완료");
User user2 = dao.get(user.getId());
System.out.println(user2.getName());
System.out.println(user2.getPassword());
System.out.println(user2.getId() + " 호출 완료");
}
NUserDao와 DUserDao가 Connection을 생성하는 방법이 다르므로, 팩토리 메소드 패턴으로 볼 수 있다.