This lesson was translated automatically – it may contain errors.
Objects should be created by the class that mostly uses them: aggregates them or calls their methods.
Who should create the object
Object A should create object B if at least one of these holds:
- A contains or aggregates B objects – keeps them as a property or a collection;
- A actively uses B objects – the bulk of the work with B goes through A;
- A holds B’s initialisation data – every time a B is created the data comes from A.
public class Order
{
private readonly List<OrderItem> _items = new();
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
public void AddItem(Product product, int quantity)
{
_items.Add(new OrderItem(product, quantity, product.Price));
}
}
class Order {
public:
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
void AddItem(const Product& product, int quantity) {
items_.emplace_back(product, quantity, product.price);
}
private:
std::vector<OrderItem> items_;
};
type Order struct {
items []OrderItem
}
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
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] = []
# The order aggregates the items and knows the data to create them –
# so it is the one that creates them
def add_item(self, product: Product, quantity: int) -> None:
self._items.append(OrderItem(product, quantity, product.price))
class Order {
private readonly items: OrderItem[] = [];
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
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<>();
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
public void addItem(Product product, int quantity) {
items.add(new OrderItem(product, quantity, product.getPrice()));
}
}
class Order {
private val items = mutableListOf<OrderItem>()
// The order aggregates the items and knows the data to create them –
// so it is the one that creates them
fun addItem(product: Product, quantity: Int) {
items += OrderItem(product, quantity, product.price)
}
}
Relation to the other principles
Creator goes together with Information Expert and Low Coupling: only the one that uses the objects should know about them.
What it does not go together with is dependency injection, where many objects are created at application start-up and then injected into each other by a DI mechanism. That is not a contradiction but different layers: domain objects are usually created by a Creator, services – by the container.