The GRASP "Creator" heuristic lists several criteria for choosing a creating class (aggregates, contains, records, closely uses, has initializing data). What does each mean, and how do you decide when two candidate classes both qualify?
answer
- aggregates > contains > records > closely uses
- init-data criterion = Information Expert
- tie-break: owner of lifetime first
- "who must expose state if not X?"
- cohesion/coupling can veto Creator
basics
~20 sAggregates/contains means it holds the object; records means it logs instances; closely uses means it works with it heavily; has initializing data means it already knows the constructor arguments. If several fit, prefer the owner (aggregator/container); otherwise the one with the data.
solid answer
~50 sThe criteria are ranked by how strongly they imply an existing dependency and lifetime ownership. *Aggregates* is whole-part with ownership — the part dies with the whole (Order/OrderLine). *Contains* is weaker: it merely holds references in a field or collection. *Records* means it keeps a registry or history of instances it does not necessarily own (AuditLog/AuditEntry, Board/Move). *Closely uses* means intimate collaboration without storage (HttpClient/Request). *Has initializing data* means it is the Information Expert for the constructor arguments, so choosing it avoids shuttling data across objects just to build one. When multiple candidates qualify, prefer aggregation/containment, because the owner can enforce invariants and control lifetime; use the initializing-data criterion as the tie-break, since the alternative forces you to expose or pass that data. If satisfying Creator would make a class incohesive or force it to import infrastructure, override it with a factory (Pure Fabrication) — Low Coupling and High Cohesion outrank Creator.
go deeper
Define two or three criteria correctly with an example each; know that the container/owner is usually the creator.
Give all five with distinct examples, explain aggregation vs containment, and state the tie-break ordering.
Add the veto rule (High Cohesion / Low Coupling override Creator), the 'what has to change if X doesn't create it?' test, and the infrastructure-in-entity failure mode.
Discuss creation as an invariant boundary: aggregate roots as the only legal creators of their parts, parameter objects for ambient context, and separating creation from reconstitution in persistence.
## Setting the scene **GRASP Creator** answers: *who instantiates class `A`?* It offers five candidate conditions on a class `B`. In real designs more than one usually holds, so you need both the definitions and a tie-break policy. ## Criterion by criterion ### 1. `B` **aggregates** `A` Aggregation (in the strong, *composition* sense) is a whole–part relationship **with lifetime ownership**: the parts do not exist independently of the whole and are destroyed with it. - `Order` aggregates `OrderLine`; a line has no meaning outside its order. - `Invoice` aggregates `InvoiceItem`; `Document` aggregates `Paragraph`. This is the strongest signal, because whoever owns the lifetime should decide the *beginning* of that lifetime, and because the owner is the only place invariants across the parts (totals, ordering, uniqueness) can be maintained. ### 2. `B` **contains** `A` Weaker: `B` holds references to `A` in a field or collection, but `A` may outlive `B` or be shared. - `Playlist` contains `Track` references (tracks exist independently). - A `Cart` contains `Product` references but does not own products. Containment still means the dependency `B → A` exists, so creation there is free — but be careful: if `A` is *shared* rather than owned, `B` may be the wrong place to create it (see the `Cart`/`Product` case: the cart contains products but definitely should not create them; it creates `CartItem` instead). ### 3. `B` **records** `A` `B` maintains a log/registry/history of `A` instances without owning the underlying subject. - `AuditLog` records `AuditEntry`. - `ChessBoard` records `Move`. - `MonitoringSession` records `Sample`. Recording implies `B` sees every instance and usually holds the timestamp/sequence data needed to build one — so it is a natural creator. ### 4. `B` **closely uses** `A` No storage, but intimate collaboration: `B` calls `A` heavily or `A` exists mainly to serve `B`'s algorithm. - `HttpClient` closely uses `Request`/`Response`. - `Parser` closely uses `Token`. - `ReportGenerator` closely uses `ReportSection`. Weakest of the structural criteria; often several classes "closely use" the same type, which is why it rarely decides on its own. ### 5. `B` **has the initializing data** for `A` This is **Information Expert** applied to construction: `B` already holds every value `A`'s constructor demands. - `Payment` knows amount and currency, so it creates `Money`. - `Sale` knows the date and total, so it creates `PaymentRecord`. This criterion is decisive because violating it has a visible cost: you must add getters, pass parameter bundles, or leak internal state purely so a different class can call `new`. ## Tie-break policy When several classes qualify, apply this order of preference: 1. **Aggregation / composition (ownership of lifetime).** The owner both creates and destroys; invariants live there. 2. **Has the initializing data.** Choosing otherwise forces data exposure — a concrete, measurable coupling cost. 3. **Containment**, then **records**, then **closely uses**. 4. **Falsify with the evaluative principles.** If the winner would become incohesive, or would have to import infrastructure (DB, clock, HTTP, config), reject it and use a **factory** — a **Pure Fabrication** class invented solely to hold construction logic. A useful practical test: *"If class X does not create it, what has to change?"* If the answer is "X must expose internal state" or "a third class must learn about two more types", X is the Creator. ## Worked conflict example A `Warehouse` records `StockMovement`s; a `Shipment` aggregates the `StockMovement`s it caused; the `ShipmentService` has the timestamp and user id. - Aggregation wins over recording: `Shipment` creates the movements it caused, and `Warehouse` merely records them. - The timestamp/user id is *context*, not domain ownership; pass it in as a parameter object rather than moving creation to the service. Passing data downward is cheap; moving ownership upward is expensive. ## Known failure modes - **Anemic creation:** a service builds every object with `new` and setters; entities become data bags and invariants live nowhere. - **God creator:** one aggregate creates everything remotely related, becoming incohesive. High Cohesion overrides Creator. - **Creator through infrastructure:** an entity that needs a repository or clock to construct a part — inject the value (`now`, generated id) as a parameter instead of injecting the service into the entity. - **Confusing creation with reconstitution:** ORMs/deserializers rebuild objects reflectively; that path bypasses the Creator and should not be used as the excuse to make constructors public everywhere.
- A Cart contains Products — does Creator say the Cart should create Products?No. Containment of a shared, independently-owned entity is not ownership. The cart creates CartItem (which it truly aggregates and whose quantity data it holds) and merely references the Product supplied to it.
- The winning Creator candidate would need a clock and an ID generator to build the part. What do you do?Don't inject infrastructure into a domain object. Pass the already-resolved values (timestamp, generated id) as constructor/method parameters from the application layer, or move construction to a factory that receives those collaborators.
- How does Creator differ from Information Expert?Information Expert is the general rule — assign a responsibility to the class holding the needed information. Creator is the specialization of it for the specific responsibility of instantiation, plus extra structural criteria (aggregation, containment, recording, close use) that Information Expert alone doesn't mention.