Skip to main content

Composing Objects Principle

Assemble complex behavior from small objects with one job each, rather than growing one object that learns to do everything itself.

Favor Composition over Inheritance is about one specific fork in the road: when a new variant shows up, do you extend a parent or hold a reference? The Composing Objects Principle is the more general version, and it doesn't need an inheritance tree to be in the picture at all.

Why it exists

It is a warning against the "god object" - a single class that has grown a method for every responsibility the system needs, because adding one more method to the class you already have was always the path of least resistance. Nobody decides to build a god object on purpose; it accretes one reasonable-looking method at a time, until the class that started as Company also runs payroll, files taxes, and books conference rooms.

A god object, decomposed

Go back to the software company. Nothing here needs a class hierarchy - there is no Company subclass in sight - but a Company that implements hiring, payroll, tax filing, client pitches, and office leasing itself, all as its own methods touching its own sprawling field list, has the same disease inheritance gets blamed for: one object doing five jobs, none of them cohesive with the others.

Company- recruiting- payroll- accounting- pr- facilities+ hire()+ runPayroll()+ fileTaxes()+ pitchClient()+ bookOffice()RecruitingDesk+ hire()PayrollService+ run()Accounting+ fileTaxes()PRDesk+ pitchClient()Facilities+ bookOffice()
composition
Company still answers five kinds of request. It personally knows how to do zero of them.

Company keeps every one of its public methods - callers notice nothing - but each method is now one line of delegation to an object whose entire reason to exist is that one job. Add a sixth responsibility later and it is a sixth small class, wired in next to the other five, not a sixth method competing for space in an already-overloaded one.

Try it yourself: Company.hire() above delegates to RecruitingDesk. What would you do if RecruitingDesk.hire() itself grew to also handle background checks, salary negotiation, and onboarding paperwork - is that a job for a sixth collaborator, or is three sub-steps inside one cohesive "hiring" responsibility still one job?

The cost of overapplying it

Not every class with three fields and two methods is a god object waiting to be rescued. A class whose fields and methods genuinely always change together for one reason doesn't need five collaborator objects standing in for what was already one cohesive job - splitting it adds navigation overhead (five files instead of one) for a cohesion problem that was never actually there. The signal to decompose is methods that pull in different directions, not merely more than one method existing.

How it relates to its neighbours

The distinction from Favor Composition over Inheritance is worth being precise about: that principle is specifically about replacing a class hierarchy - "should this be an is-a subclass or a has-a field?" This principle is the general case, applying just as forcefully to a Company that never had a subclass anywhere near it. Every "should this be a subclass" question is composition over inheritance. Every "why does this one class do five unrelated things" question is the Composing Objects Principle, hierarchy or not. It is also Separation of Concerns's conclusion applied to a single object instead of a whole program - Company above is a smaller-scale version of exactly the same move OrderImportJob goes through on that page.

Where you'll see it in the pattern catalog

Facade often wraps exactly the kind of collaborators this principle produces, giving external callers one simple door into Company's five delegated jobs. Mediator applies the same "small single-job objects, coordinated" idea when those objects also need to talk to each other, not just be called by one coordinator.

Check yourself

Question 1 of 3

How is the Composing Objects Principle different from "favor composition over inheritance," given both end up with one object holding references to others?