팩터리 메서드 패턴은 객체 생성을 직접 하는 대신, 객체 생성을 처리하는 메서드를 통해 객체를 만드는 디자인 패턴입니다. 이 패턴은 객체 생성 로직을 캡슐화하여 코드의 유연성과 재사용성을 높입니다.
데이터베이스 연결을 예시로 들어보겠습니다.
여러 종류의 데이터베이스(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 인터페이스를 통해 데이터베이스 작업을 수행합니다.