In the Observer pattern, an observable subject maintains subscriptions and sends notifications through a common observer interface when a relevant change occurs. Observers can then react to the event or query the subject's coherent new state. Registration and removal allow multiple dependants to change independently of the subject's application logic.
It is useful when one software object has several changing dependants, for example a document model with several views or a text field with an event handler. It avoids hard-coding every concrete dependant into the subject, reducing direct coupling and duplicated synchronization logic. Clients need not poll repeatedly to detect a change. This separation does not automatically prevent notification cycles, stale subscriptions, or inconsistent intermediate states: notification should occur after a coherent update, and observers should unregister when no longer needed. A reentrant event handler can otherwise commit recursively while refreshing a display.
Choose a deterministic editing policy: editing pounds or the exchange rate preserves the pounds amount and recalculates euros; editing euros preserves the rate and recalculates pounds. A valid rate must be finite and positive; amounts may be any finite signed number. Keep an unrounded numeric model, so repeatedly refreshing a two-decimal display does not feed rounded text back into the computation. Place the following members inside the supplied MainFrame, after its fields are created:
private var poundsValue = 10.0
private var eurosValue = 11.5
private var rateValue = 1.15
private var refreshing = false

private def finite(x: Double): Boolean =
  !java.lang.Double.isNaN(x) && !java.lang.Double.isInfinite(x)

private def number(s: String): Option[Double] =
  scala.util.Try(s.trim.toDouble).toOption.filter(finite)

private def money(x: Double): String =
  java.lang.String.format(java.util.Locale.ROOT, "%.2f",
                          java.lang.Double.valueOf(x))

private def refresh(): Unit = {
  refreshing = true
  try {
    pounds.text = money(poundsValue)
    euros.text = money(eurosValue)
    rate.text = money(rateValue)
  } finally {
    refreshing = false
  }
}

private def commit(p: Double, e: Double, r: Double): Unit = {
  if (finite(p) && finite(e) && finite(r) && r > 0.0) {
    poundsValue = p
    eurosValue = e
    rateValue = r
    refresh()
  }
}

listenTo(pounds, euros, rate)
reactions += {
  case EditDone(source) if !refreshing =>
    number(source.text).foreach { value =>
      if (source eq pounds)
        commit(value, value * rateValue, rateValue)
      else if (source eq euros)
        commit(value / rateValue, value, rateValue)
      else if ((source eq rate) && value > 0.0)
        commit(poundsValue, poundsValue * value, value)
    }
}
The mathematical model invariant is with a positive rate. In floating-point arithmetic, each update establishes the corresponding rounded multiplication or division; a division followed by multiplication need not recover bitwise identical values. Pounds and rate edits calculate a matching euro amount, while euro edits calculate its matching pound amount. An invalid parse, a nonpositive rate, or a nonfinite calculated result leaves the last valid numeric model unchanged. An invalid text entry may remain visible until corrected or a subsequent valid refresh; a production interface could add a validation message.
Every accepted edit refreshes the fields from that model. Locale.ROOT makes the decimal separator match the toDouble parser, independently of the machine's locale. The guard prevents a synchronous reentrant event handler from interpreting a refresh as another user commit. The displayed values are rounded to two decimal places, including the rate, while the stored values retain full Double precision. Very small positive rates can therefore display as 0.00; using more rate digits is a reasonable presentation refinement. Pounds, euros and rate edits all propagate by the stated policy, with no parsing exception or division by zero.
EditDone handles completion of an edit, such as an action or focus-change notification, using the event type supplied in the paper. It is not a promise of recalculation after every keystroke. A character-by-character interface would subscribe to the corresponding text-change event instead. The publisher/reactor interaction follows the supplied contract and official Scala Swing documentation; no exact course library build or native graphical execution is presumed.[ref]
In the Observer pattern, a subject maintains subscriptions through a common observation interface. Interested observers register and unregister; when a relevant state change occurs, the subject sends a notification, and each observer runs its own reaction. Notifications can carry the new information directly or prompt the observer to query the subject's coherent updated state.
This fits an event-driven programming interface in which one model can have several independently changing views: a displayed conversion, a chart or a status indicator can react to the same model change. It avoids hard-coding calls to every concrete view inside the subject, which would couple domain logic to presentation details and require editing the subject whenever another view is added. The subject depends on the observer interface rather than every concrete observer class.
The design still needs subscription cleanup and an update policy. Mutual notifications can create a feedback loop or a reentrant event handler, while an observer that reacts halfway through a state change can see inconsistent data. Publishing only coherent changes and controlling derived display updates address those problems; the pattern alone does not automatically solve them.