※설계도로서의 팩토리(Factory as Design)는 객체 지향 설계에서 객체 생성과 관련된 문제를 해결하기 위한 방법 중 하나입니다. 이 패턴은 객체 생성 로직을 추상화하여, 구체적인 객체 생성 방법에 대한 결정을 미루고, 유연하게 대처할 수 있는 방법을 제공합니다.
설계도로서의 팩토리 패턴은 다음과 같은 구성 요소로 이루어져 있습니다.
Creator: 객체 생성 메서드를 제공하는 추상 클래스 또는 인터페이스입니다. Creator 클래스는 객체 생성 메서드를 추상화하고, 구체적인 객체 생성 방법을 미룹니다.
ConcreteCreator: Creator를 구현한 클래스입니다. ConcreteCreator 클래스는 객체 생성 메서드를 구현하고, 구체적인 객체 생성 방법을 결정합니다.
Product: 생성되는 객체를 나타내는 클래스입니다. Product 클래스는 ConcreteCreator 클래스에 의해 생성됩니다.
ConcreteProduct: Product를 구현한 클래스입니다. ConcreteProduct 클래스는 실제로 생성될 객체를 나타냅니다.
설계도로서의 팩토리 패턴은 다양한 상황에서 사용될 수 있습니다. 예를 들어, 객체 생성에 대한 책임을 모듈로부터 분리하여, 모듈 간의 결합도를 낮출 수 있습니다. 또한, 객체 생성에 대한 로직을 추상화함으로써, 객체 생성 방법을 변경할 때 유연하게 대처할 수 있습니다.
다음은 설계도로서의 팩토리 패턴을 사용한 Java 코드 예시입니다.
// Creator
public abstract class AnimalFactory {
public abstract Animal createAnimal();
}
// ConcreteCreator
public class DogFactory extends AnimalFactory {
public Animal createAnimal() {
return new Dog();
}
}
// ConcreteCreator
public class CatFactory extends AnimalFactory {
public Animal createAnimal() {
return new Cat();
}
}
// Product
public interface Animal {
void speak();
}
// ConcreteProduct
public class Dog implements Animal {
public void speak() {
System.out.println("Woof!");
}
}
// ConcreteProduct
public class Cat implements Animal {
public void speak() {
System.out.println("Meow!");
}
}
// Client
public class Client {
private AnimalFactory animalFactory;
public void setAnimalFactory(AnimalFactory animalFactory) {
this.animalFactory = animalFactory;
}
public void speakAnimal() {
Animal animal = animalFactory.createAnimal();
animal.speak();
}
}
// Main class
public class Main {
public static void main(String[] args) {
Client client = new Client();
client.setAnimalFactory(new DogFactory());
client.speakAnimal();
client.setAnimalFactory(new CatFactory());
client.speakAnimal();
}
}
위 코드에서, AnimalFactory 클래스는 객체 생성 메서드를 추상화하고, 구체적인 객체 생성 방법을 미룹니다.
DogFactory와 CatFactory는 AnimalFactory를 구현하여, 구체적인 객체 생성 방법을 결정합니다.
Animal 인터페이스는 생성될 객체를 추상화하며, Dog와 Cat 클래스는 Animal 인터페이스를 구현하여, 실제로 생성될 객체를 나타냅니다.
Client 클래스는 AnimalFactory 객체를 생성하고, speakAnimal() 메서드를 호출하여 생성된 객체의 speak() 메서드를 실행합니다. Main 클래스에서는 Client 객체를 생성하고, setAnimalFactory() 메서드를 호출하여 객체 생성 방법을 설정합니다. 이를 통해, 생성될 객체의 타입을 변경할 수 있습니다.
설계도로서의 팩토리 패턴은 객체 생성과 관련된 문제를 해결하기 위한 방법 중 하나이며, 객체 지향 설계에서 중요한 역할을 합니다. 팩토리 패턴은 객체 생성 로직을 추상화하여 유연성과 확장성을 높이는 데 도움을 주며, 다른 객체 지향 디자인 패턴과 함께 사용하여 더욱 유연하고 확장 가능한 소프트웨어를 만들 수 있습니다.
앱을 구성하는 컴포넌트의 구조와 관계를 정의한 설계도 같은 역할을 하는 DaoFactory.
UserDao와 ConnectionMaker는 각각 앱의 핵심적인 데이터 로직과 기술 로직을 담당하고 있고, DaoFactory는 이런 앱의 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있습니다.
새로운 ConnectionMaker 구현 클래스 추가 또는 변경이 필요하면 DaoFactory를 수정해서 변경된 클래스를 생성해 설정해 주도록 코드를 수정해주면 됩니다.
이로 인해 데이터베이스 데이터 조작 작업의 핵심 기능을 담당하는 UserDao의 변경이 필요[새로운 ConnectionMaker 구현 클래스 추가 또는 변경로 인한] 없으므로 안전하게 UserDao의 소스코드를 보존할 수 있습니다.
동시에 DB 연결 방식은 자유로운 확장이 가능합니다.
DaoFactory를 분리했을 때 얻을 수 있는 장점은 매우 다양합니다.
그 중에서도 앱의 컴포넌트 역할을 하는 오브젝트와 앱의 구조를 결정하는 오브젝트를 분리했다는 데 큰 의미가 있습니다.
DaoFactory에 UserDao가 아닌 다른 DAO 생성 기능을 추가할 수도 있습니다.
public class DaoFactory {
public UserDao userDao() {
ConnectionMaker connectionMaker = new DConnectionMaker();
UserDao userDao = new UserDao(connectionMaker);
return userDao;
}
public AccountDao accountDao() {
ConnectionMaker connectionMaker = new DConnectionMaker();
AccountDao accountDao = new AccountDao(connectionMaker);
return accountDao;
}
public MessageDao messageDao() {
ConnectionMaker connectionMaker = new DConnectionMaker();
MessageDao messageDao = new MessageDao(connectionMaker);
return messageDao;
}
}
위 코드는 여러 개의 Dao들을 생성하는 팩토리이긴 하지만,
ConnectionMaker 구현 클래스를 생성하는 동일한 코드가 반복되어서 나타나는 문제점이 있습니다.
이러한 중복 문제를 해결하기 위해 다음 코드처럼 리팩토링 작업을 합니다.
public class DaoFactory {
public UserDao userDao() {
return new UserDao(connectionMaker());
}
public AccountDao accountDao() {
return new AccountDao(connectionMaker());
}
public MessageDao messageDao() {
return new MessageDao(connectionMaker());
}
public ConnectionMaker connectionMaker() {
return new DConnectionMaker();
}
}