M4 — State, Identity, and Global Access

SENG 365 — Software Engineering

Neil Ernst

University of Victoria

2026-10-01

Module Goals

Design Judgement

By the end of this module, you should be able to:

  • derive meaningful abstract states from concrete fields;
  • identify and prevent illegal transitions;
  • distinguish identity, equality, uniqueness, and immutability; and
  • compare a Singleton, dependency injection, and domain-enforced uniqueness.

State and State Diagrams

Preparation

Before class: Read Chapter 4, Sections 4.1–4.3.

Entry Decision

A vending machine has balance = 200 and selection = null.

Is its state “200 and null,” “has credit,” “awaiting selection,” or something else? What decision would your answer help make?

A State-Heavy Method

void press(String input) {
    if (timedOut) reset();
    else if (input.equals("coin")) balance += 100;
    else if (input.equals("cancel")) reset();
    else if (selection == null) selection = input;
    else if (balance >= price(selection)) vend();
    else display("more credit required");
}

Concrete fields record values. Abstract states explain what operations are meaningful.

What combinations of fields are possible but nonsensical?

Model the Lifecycle

Produce a state diagram containing:

  • meaningful abstract states;
  • events that trigger transitions;
  • a guard where price or balance matters;
  • timeout and reset behaviour; and
  • one illegal transition the implementation must prevent.

Keep a separate list of concrete fields that may implement each abstract state.

Put the Model Under Pressure

Revise the diagram for one of the following changes:

  • a selection may occur before payment;
  • card authorization is asynchronous;
  • a refund may fail;
  • inventory runs out after selection; or
  • the machine remembers a previous selection.

Which “state” was really an implementation detail?

Transfer: a UVic Course

  • Course offering: planned, open, full, in progress, grades submitted, archived.

Name states with nouns or stable conditions; name transitions with events.

Distinguish the state of the real world from the software’s record of it.

Synthesis

  • Static structure and run-time state are complementary views.
  • Abstract states should explain behaviour, not code field values.
  • Minimize meaningful states and make illegal states hard to represent.
  • Understanding state is an important way to test and find errors.
  • null, temporary fields, and convenience flags often expand the state space.
  • A state diagram is valuable when it changes a design decision.

Exit Note

The implementation must make __________ unrepresentable because __________.

Identity, Equality, and Global Access

Preparation

Before class: Read Chapter 4, Sections 4.4–4.8.

Entry Decision

Card a = new Card(Rank.ACE, Suit.CLUBS);
Card b = new Card(Rank.ACE, Suit.CLUBS);

Should a == b be true? Should a.equals(b) be true? Should both objects be allowed to exist?

Answer all three before choosing an implementation.

Convenient Global Access

final class GameModel {
    private static final GameModel INSTANCE = new GameModel();
    static GameModel instance() { return INSTANCE; }

    private int score;
    void addPoints(int points) { score += points; }
    int score() { return score; }
}
class ScoreTest {
    @Test void startsAtZero() {
        assertEquals(0, GameModel.instance().score());
    }
}

Why might this test pass alone and fail after another test?

Compare Three Designs

Compare:

  1. globally accessible Singleton GameModel;
  2. an explicitly injected GameModel; and
  3. ordinary game objects with a domain rule that identifies the current game.

For each, record:

  • how clients obtain the object;
  • whether the dependency is visible;
  • how tests isolate state;
  • how uniqueness is enforced; and
  • what happens if two games are needed later.

Uniqueness Is Not One Thing

  • Identity: two references point to the same object.
  • Equality: two objects represent equivalent values.
  • Uniqueness: the domain or design permits only one matching object.
  • Immutability: an object’s value cannot change after construction.

An immutable value need not be unique. A unique object need not be immutable.

Creation Choices

  • A value object normally defines equals() and hashCode().
  • Flyweight can reuse immutable instances when identity does not carry domain meaning.
  • Singleton controls construction and global access to one class instance.
  • Dependency injection can share one instance without hiding how clients receive it.

Do not turn “we only need one today” into an unexamined global dependency.

Null and Optional

Absence is part of the state model:

Optional<Player> winner()

Use Optional or a Null Object when absence is meaningful and the resulting interface is clearer. Do not use null merely because it is convenient.

Compare Alternatives

  • Is uniqueness a domain invariant or an implementation convenience?
  • Must clients share state?
  • Can tests create a fresh instance?
  • Does global access hide dependencies?
  • What behaviour should equality capture?
  • Which future requirement breaks each choice?

Exit Note

Uniqueness is a domain rule when __________.

It is merely convenient when __________.