GRASP 패턴: Creator (생성자)
Prof. Jong Min Lee이(가) 약 한달 전에 추가함
GRASP 패턴: Creator (생성자) - 간단한 설명과 예시¶
핵심 아이디어: 객체를 생성해야 할 때, 어떤 클래스가 그 객체를 생성하는 책임을 맡아야 하는가에 대한 지침을 제공합니다. 객체 생성의 책임을 적절한 클래스에 할당함으로써 시스템의 결합도를 낮추고 객체 생성을 캡슐화합니다.
간단한 설명:
객체 생성은 객체 지향 시스템에서 흔히 발생하는 작업입니다. Creator 패턴은 이 생성 책임을 누가 가져야 하는지에 대한 몇 가지 일반적인 지침을 제시합니다. 일반적으로 객체 A가 객체 B를 생성해야 할 때, 다음 조건 중 하나 이상을 만족하는 경우 A에게 B를 생성하는 책임을 할당하는 것이 좋습니다.
- A가 B 객체를 포함하거나 구성한다. (Composition)
- A가 B 객체를 긴밀하게 사용한다.
- A가 B 객체를 생성하는 데 필요한 초기화 정보를 가지고 있다.
- A가 B 객체 생성의 전문가이다. (Factory)
예시:
Order
객체와 OrderItem
객체를 생각해 봅시다. 하나의 주문(Order
)은 여러 개의 주문 아이템(OrderItem
)으로 구성됩니다. 각 OrderItem
은 주문한 상품과 수량 정보를 담고 있습니다.
class Order {
private List<OrderItem> orderItems;
public Order() {
this.orderItems = new ArrayList<>();
}
public void addOrderItem(OrderItem item) {
this.orderItems.add(item);
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
}
class OrderItem {
private String productCode;
private int quantity;
private double price;
public OrderItem(String productCode, int quantity, double price) {
this.productCode = productCode;
this.quantity = quantity;
this.price = price;
}
// ... getter 메서드 ...
}
public class Client {
public static void main(String[] args) {
Order order = new Order();
OrderItem item1 = new OrderItem("A123", 2, 10000);
OrderItem item2 = new OrderItem("B456", 1, 25000);
// Client에서 OrderItem 객체를 직접 생성하여 Order에 추가
order.addOrderItem(item1);
order.addOrderItem(item2);
// ...
}
}
위의 예시에서 Client
클래스는 Order
와 OrderItem
객체를 모두 생성하고 있습니다. 하지만 Order
는 OrderItem
들을 포함하고 관리하는 역할을 하므로, Order
가 OrderItem
을 생성하는 책임을 갖는 것이 더 자연스러울 수 있습니다. 이는 A가 B 객체를 포함하거나 구성한다는 Creator 패턴의 지침에 부합합니다.
Creator 패턴을 적용하면 다음과 같이 설계를 변경할 수 있습니다.
class Order {
private List<OrderItem> orderItems;
public Order() {
this.orderItems = new ArrayList<>();
}
// OrderItem 생성 책임을 Order 클래스에게 할당
public void addOrderItem(String productCode, int quantity, double price) {
OrderItem newItem = new OrderItem(productCode, quantity, price);
this.orderItems.add(newItem);
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
}
class OrderItem {
private String productCode;
private int quantity;
private double price;
public OrderItem(String productCode, int quantity, double price) {
this.productCode = productCode;
this.quantity = quantity;
this.price = price;
}
// ... getter 메서드 ...
}
public class Client {
public static void main(String[] args) {
Order order = new Order();
// Order를 통해 OrderItem 객체를 생성
order.addOrderItem("A123", 2, 10000);
order.addOrderItem("B456", 1, 25000);
// ...
}
}
변경된 설계의 장점:
- 낮은 결합도:
Client
클래스는OrderItem
객체의 생성 방식에 대해 알 필요가 없어집니다.Order
클래스가 내부적으로OrderItem
을 어떻게 생성하는지 캡슐화됩니다. - 객체 생성 캡슐화:
Order
클래스는OrderItem
생성 로직을 중앙 집중화하여 관리할 수 있습니다. 만약OrderItem
생성 방식이 변경되더라도Order
클래스만 수정하면 됩니다. - 응집도 향상:
Order
클래스는 자신이 관리하는OrderItem
의 생성 책임까지 가지게 되어 응집도가 높아질 수 있습니다.
물론 객체 생성 책임은 위 예시처럼 단순하지 않을 수 있습니다. 복잡한 객체 생성 로직이 필요한 경우에는 Factory 패턴과 같은 다른 생성 관련 패턴을 활용하는 것이 더 적절할 수 있습니다. Creator 패턴은 객체 생성 책임을 "자연스럽게" 가져야 하는 클래스를 식별하는 데 도움을 줍니다.