Программа курса← Объектно ориентированное программирование
1История ООП
2Объект и Класс
3Базовые концепции ООП
4Принцип проектирования GRASP
5Принцип проектирования SOLID
6Паттерны GOF

Creator (Создатель)

TODO: отвалидировать – текст собран автоматически из материалов курса на Google Drive, проверьте формулировки и код.

Создавать объекты должен тот класс, который эти объекты преимущественно использует: агрегирует их или вызывает их методы.

Кто должен порождать объект

Объект A должен порождать объект B, если выполняется хотя бы одно:

  • A содержит или агрегирует объекты B – держит их как свойство или коллекцию;
  • A активно использует объекты B – основной объём работы с B идёт через A;
  • A обладает данными инициализации B – при каждом создании B данные берутся из A.
public class Order
{
    private readonly List<OrderItem> _items = new();

    // Заказ агрегирует позиции и знает данные для их создания –
    // значит, он же их и создаёт
    public void AddItem(Product product, int quantity)
    {
        _items.Add(new OrderItem(product, quantity, product.Price));
    }
}
class Order {
public:
    // Заказ агрегирует позиции и знает данные для их создания –
    // значит, он же их и создаёт
    void AddItem(const Product& product, int quantity) {
        items_.emplace_back(product, quantity, product.price);
    }

private:
    std::vector<OrderItem> items_;
};
type Order struct {
	items []OrderItem
}

// Заказ агрегирует позиции и знает данные для их создания –
// значит, он же их и создаёт
func (o *Order) AddItem(product Product, quantity int) {
	o.items = append(o.items, OrderItem{
		Product:  product,
		Quantity: quantity,
		Price:    product.Price,
	})
}
class Order:
    def __init__(self) -> None:
        self._items: list[OrderItem] = []

    # Заказ агрегирует позиции и знает данные для их создания –
    # значит, он же их и создаёт
    def add_item(self, product: Product, quantity: int) -> None:
        self._items.append(OrderItem(product, quantity, product.price))
class Order {
    private readonly items: OrderItem[] = [];

    // Заказ агрегирует позиции и знает данные для их создания –
    // значит, он же их и создаёт
    addItem(product: Product, quantity: number): void {
        this.items.push(new OrderItem(product, quantity, product.price));
    }
}
public class Order {
    private final List<OrderItem> items = new ArrayList<>();

    // Заказ агрегирует позиции и знает данные для их создания –
    // значит, он же их и создаёт
    public void addItem(Product product, int quantity) {
        items.add(new OrderItem(product, quantity, product.getPrice()));
    }
}
class Order {
    private val items = mutableListOf<OrderItem>()

    // Заказ агрегирует позиции и знает данные для их создания –
    // значит, он же их и создаёт
    fun addItem(product: Product, quantity: Int) {
        items += OrderItem(product, quantity, product.price)
    }
}

Связь с другими принципами

Creator сочетается с Information Expert и с Low Coupling: знать об объектах должен только тот, кто их использует.

При этом принцип не сочетается с концепцией Dependency Injection, при которой многие объекты создаются при старте приложения, а затем внедряются друг в друга DI-механизмом. Это не противоречие, а разные слои: доменные объекты обычно создаёт Creator, а сервисы – контейнер.