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()
}