프로젝트

일반

사용자정보

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 클래스는 OrderOrderItem 객체를 모두 생성하고 있습니다. 하지만 OrderOrderItem들을 포함하고 관리하는 역할을 하므로, OrderOrderItem을 생성하는 책임을 갖는 것이 더 자연스러울 수 있습니다. 이는 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 패턴은 객체 생성 책임을 "자연스럽게" 가져야 하는 클래스를 식별하는 데 도움을 줍니다.