팩터리 메서드 패턴은 객체 생성을 직접 하는 대신, 객체 생성을 처리하는 메서드를 통해 객체를 만드는 디자인 패턴입니다. 이 패턴은 객체 생성 로직을 캡슐화하여 코드의 유연성과 재사용성을 높입니다.
데이터베이스 연결을 예시로 들어보겠습니다.
여러 종류의 데이터베이스(MySQL, PostgreSQL 등)에 연결해야 하는 애플리케이션이 있습니다.
각 데이터베이스는 연결 방식이 조금씩 다르고 사용하는 드라이버가 다르며 쿼리 문법에도 일부 차이가 있을 수 있습니다.
우선 팩터리 메서드 패턴을 적용하지 않았을 때의 코드입니다.
public interface DatabaseConnection {
void connect();
void executeQuery(String query);
void close();
}
class MySQLConnection implements DatabaseConnection {
// Implementation
}
class PostgreSQLConnection implements DatabaseConnection {
// Implementation
}
public class DatabaseClient {
private DatabaseConnection connection;
public DatabaseClient(String databaseType) {
if ("MySQL".equals(databaseType)) {
this.connection = new MySQLConnection();
} else if ("PostgreSQL".equals(databaseType)) {
this.connection = new PostgreSQLConnection();
} else {
throw new IllegalArgumentException("Unsupported database type: " + databaseType);
}
this.connection.connect();
}
public void executeQuery(String query) {
try {
this.connection.executeQuery(query);
} catch (Exception e) {
// 예외 처리
System.err.println("Query execution failed: " + e.getMessage());
}
}
public void close() {
if (this.connection != null) {
this.connection.close();
}
}
}
연결해야 하는 데이터베이스가 추가될 때마다 코드는 수정되어야 합니다. 이 코드는 OCP(Open-Closed Principle)를 위반하였습니다.
또한 DatabaseClient가 구체적인 데이터베이스 구현에 직접 의존하고 있습니다.
private DatabaseConnection connection;
...
this.connection = new MySQLConnection();
this.connection = new PostgreSQLConnection();
DatabaseClient 클래스는 구체적인 클래스인 MySQLConnection과 PostgreSQLConnection을 직접 인스턴스화하고 있다고 하는데요, 이는 다음과 같은 문제를 야기합니다.
DatabaseClient
가 특정 데이터베이스 구현의 존재를 알아야 합니다.DatabaseClient
클래스를 수정해야 합니다.그럼 팩터리 메서드 패턴을 이용하여 위와 같은 문제점들을 수정해보겠습니다.
먼저, 데이터베이스 연결을 위한 인터페이스를 정의합니다.
public interface DatabaseConnection {
void connect();
void executeQuery(String query);
void close();
}
이제 데이터베이스 연결들을 DatabaseConnection 인터페이스를 이용하여 구현합니다.
public class MySQLConnection implements DatabaseConnection {
@Override
public void connect() {...}
@Override
public void executeQuery(String query) {...}
@Override
public void close() {...}
}
public class PostgreSQLConnection implements DatabaseConnection {
@Override
public void connect() {...}
@Override
public void executeQuery(String query) {...}
@Override
public void close() {...}
}
이제 데이터베이스 연결을 생성하는 팩터리 인터페이스를 정의합니다.
public interface DatabaseConnectionFactory {
DatabaseConnection createConnection();
}
그리고 각 데이터베이스 유형에 대한 구체적인 팩터리를 구현합니다. 팩터리 메서드 패턴의 특징인 생성한 객체도 반환해줍니다.
public class MySQLConnectionFactory implements DatabaseConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new MySQLConnection();
}
}
public class PostgreSQLConnectionFactory implements DatabaseConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new PostgreSQLConnection();
}
}
이제 이 팩터리를 사용하는 클라이언트 코드를 작성해보겠습니다.
이 코드에서는 데이터베이스 관련 로직을 처리합니다.
public class DatabaseClient {
private DatabaseConnectionFactory factory;
public DatabaseClient(DatabaseConnectionFactory factory) {
this.factory = factory;
}
public void executeQuery(String query) {
DatabaseConnection connection = factory.createConnection();
connection.connect();
connection.executeQuery(query);
connection.close();
}
}
아래 코드는 Main 클래스에서 실제로 사용하는 예시입니다.
public class Main {
public static void main(String[] args) {
// MySQL 사용
DatabaseConnectionFactory mysqlFactory = new MySQLConnectionFactory();
DatabaseClient mysqlClient = new DatabaseClient(mysqlFactory);
mysqlClient.executeQuery("SELECT * FROM users");
// PostgreSQL 사용
DatabaseConnectionFactory postgresFactory = new PostgreSQLConnectionFactory();
DatabaseClient postgresClient = new DatabaseClient(postgresFactory);
postgresClient.executeQuery("SELECT * FROM products");
}
}
DatabaseConnection
인터페이스를 생성합니다.connect()
, executeQuery()
, close()
메서드를 선언합니다.MySQLConnection
과 PostgreSQLConnection
클래스를 만들어 DatabaseConnection
인터페이스를 구현합니다.DatabaseConnectionFactory
인터페이스를 생성합니다.createConnection()
메서드를 선언합니다.MySQLConnectionFactory
와 PostgreSQLConnectionFactory
클래스를 만들어 DatabaseConnectionFactory
인터페이스를 구현합니다.createConnection()
메서드에서 해당 데이터베이스 연결 객체를 생성하여 반환합니다.DatabaseConnection
인터페이스를 통해 데이터베이스 작업을 수행합니다.