1

I find myself applying a certain pattern again and again and I assume I am not the first one. I am looking for a name.

In the environment I find myself in we get updates to values via an external interface. Based on those updates, we have to produce certain effects. Practically, our effects not only depend on the current value, but also on the history. For example, we might observe a traffic light, and if it turns red without passing yellow in between, we warn.

class TrafficLight {
    boolean red
    boolean yellow
    boolean green
    // TrafficLight part of interface -- cannot add methods
}

updateTrafficLight(TrafficLight current) {
    if (roadClear && current.red)
        log.warn( "switched from plain green to red without yellow in between!" ) // example effect
    roadClear = current.green && !current.yellow && !current.red
    
   // 50 more effects, might be organized in methods / classes
}

The main problem are flags like roadClear which extract some information from an update. Those flags are read on the next update. With the 50 other effects, the state becomes untractable and every little refactoring might introduce bugs because the sequence of setting the (previous)state and reading it might be shuffled.

These TrafficLight updates are well logged, part of the specification and analysed by external suppliers. So I often find myself refactoring this into mostly pure stateless functions that compare the previous update and the current value like this:

compareTrafficLight(TrafficLight previous, TrafficLight current) {
    if (isRoadClear(previous) && current.red)
        log.warn( "switched from plain green to red without yellow in between!" ) // example effect
}

boolean isRoadClear(TrafficLight trafficLight) {
    return trafficLight.green && !trafficLight.yellow && !trafficLight.red
}

Does this bundling of current and previous value (and avoid other state) have a name? It might be worth noting that it gives rise to a container Diff<T>. Instead of Diff, there might be an accepted name. Diff has map (Functor) and flatMap (Monad).

Diff<T> {
    T getPrevious()
    T getCurrent()
}
1
  • 4
    Anecdotally, I think you're describing a finite state machine. In fact, the Wikipedia article includes traffic lights as an example. Commented Mar 2, 2021 at 18:34

1 Answer 1

1

This has a lot in common with the Observer Pattern. I would also suggest that techniques around the Memento Pattern are relevant even though your intent is not similar. Lastly I would agree with Robert Harvey that this can also be described as a finite state machine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.