Skip to content

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 = 15
status = pending
total = 500
items = [...]

After a successful payment, part of that State may change:

status = paid

Different Objects from the same Class may have different State at the same time.

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.

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.

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.
final class Order
{
public string $status = 'pending';
public function markAsPaid(): void
{
$this->status = 'paid';
}
}
$order = new Order();
$order->markAsPaid();
echo $order->status; // paid

The 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.

  • 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 void return declaration on a Method that returns no value.
State = what is true about this Object now?
Behavior = what can this Object do with or about that State?

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.

  1. Which parts of a Wallet are State, and which are Behavior?
  2. Why is direct balance manipulation from many services risky?
  3. Why should email delivery remain outside Wallet::withdraw()?
  4. What distinguishes an anemic domain Object from a richer one?