State and Behavior
An Object is more than a container for data. It can combine its current State with Behavior that understands and changes that State.
State is the set of current values that describe one Object at a particular moment. An Order might currently have:
id = 15status = pendingtotal = 500items = [...]After a successful payment, part of that State may change:
status = paidDifferent Objects from the same Class may have different State at the same time.
Behavior
Section titled “Behavior”Behavior is what an Object can do. Methods express that Behavior:
final class Wallet{ public float $balance = 0;
public function deposit(float $amount): void { $this->balance += $amount; }
public function withdraw(float $amount): void { $this->balance -= $amount; }}balance is State. deposit() and withdraw() are Behaviors that change it.
Keep behavior near the data it governs
Section titled “Keep behavior near the data it governs”External code could manipulate the balance directly:
if ($wallet->balance >= $amount) { $wallet->balance -= $amount;}But every caller would then need to remember the same rules. A caller may forget a check or implement it differently. Asking the Wallet to perform the operation gives the rule one natural home:
$wallet->withdraw($amount);Later lessons will strengthen this design using private State and invariants.
Anemic and rich domain models
Section titled “Anemic and rich domain models”An Anemic Domain Model stores data in domain Objects while most meaningful domain Behavior lives in external services. A Rich Domain Model keeps Behavior and rules with the Objects that own the relevant information.
Rich does not mean that one Object should do everything. For example, a Wallet may decide whether a withdrawal is allowed, but it should not know SMTP or render an email template. Notification delivery is a separate responsibility.
Wallet → owns balance behavior.NotificationSender → delivers a notification.Practical example
Section titled “Practical example”final class Order{ public string $status = 'pending';
public function markAsPaid(): void { $this->status = 'paid'; }}
$order = new Order();$order->markAsPaid();
echo $order->status; // paidThe status value is State. markAsPaid() is Behavior that changes that State.
The rules that restrict this transition belong to later lessons on
Encapsulation and invariants.
Common mistakes
Section titled “Common mistakes”- Treating Objects as data bags while external services make every decision.
- Allowing many callers to repeat and disagree about the same state-change rule.
- Moving unrelated infrastructure into a domain Object in the name of a rich model.
- Assuming all data must have behavior; simple values and transformations can remain simple.
- Forgetting a
voidreturn declaration on a Method that returns no value.
Mental model
Section titled “Mental model”State = what is true about this Object now?Behavior = what can this Object do with or about that State?Summary
Section titled “Summary”State describes an Object at a moment in time. Behavior is expressed through Methods that inspect or change that State. Keeping domain behavior close to the information it governs reduces duplicated decisions, but an Object should not absorb unrelated responsibilities.
Knowledge check
Section titled “Knowledge check”- Which parts of a Wallet are State, and which are Behavior?
- Why is direct balance manipulation from many services risky?
- Why should email delivery remain outside
Wallet::withdraw()? - What distinguishes an anemic domain Object from a richer one?