Closure-Based State Explained
Patterns, 20 Years Later: With the prevalence of libraries and tools that can peer past access controls (such as Reflection on the JVM and CLR, or the Mirrors facility in Swift), trying to encapsulate private details away from prying eyes can be increasingly difficult.
Join the DZone community and get the full member experience.Join For Free
We want to preserve “information hiding” and avoid exposing details of how and where internal state is being held.
Reflection libraries can bypass “private” and other access controls. This is a good thing in a number of ways, but Reflection libraries also offer opportunities to completely undo the benefit of access controls.
The language has no concept of object. In a traditional functional language, it’s actually difficult to keep state and data tied together. In fact, part of the whole point of a functional language is towrite functions that operate on data, ideally on lots of different kinds of data. In such languages, then, when seeking to keep state and operations together, we have to get a little tricky to obtain the traditionalthings that an object-oriented language provides for free.
The language offers a closure facility around function literals. Meaning, the language knows how to “close over” local variables being referenced within scope of the function’s definition, yet outside of the function definition itself. (Almost all languages developed since 2000 offer such capability, and those that didn’t have it before, such as C++, Java, and others, have already or are being modified to include it.)
Use the closure facilities of the language to hold state referenced from within the function, thus providing thefunctionality of a private field without requiring or using that language facility.
Note that there is no reason that a given system couldn’t use both Closure-based State and the traditional privatefields within a class, so as to have those fields hidden via “private” yet still accessible via Reflection (and thusto tools that make use of Reflection, a la object-relational libraries or serialization systems), yet also have certain data entirely inaccessible to Reflection systems.
The Envoy pattern language, from which this pattern is borrowed, describe sseveral implementations as part of that pattern language.
(Additional implementations forthcoming.)
Invisible references. The closure is an “invisible reference” from the object, and the closure, along with anyadditional variables referenced from that enclosing scope. That means that potentially the Closure-based Statedata will keep more objects alive for longer than intuition suggests, which can create potential memory pressureon the program if it grows out of hand.
Strategy implementations can hold data as fields in the Strategy object itself, which essentially provides much of the same kind of functionality as Closure-based State, without the concerns around Reflection being addressed at all.
Closure-based State can fairly easily adapt to use the State pattern to adjust its internal stateand operations. Operations would be “trampolining” into functions defined in the closure, rather than on the object itself.
Published at DZone with permission of Ted Neward, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.