Can you explain the Context design pattern?
I've started to read about the Context design pattern. Here's what I understood from the text :
you have a map containing all your variables
you pass it around to whoever needs it, so that you won't have to send all the variables as method parameters
Did I "get" it?
Solution 1:
Did I "get" it?
Sorry to say, not quite.
The goal of Context Object is not to pass lots of parameters to methods implicitly, as a means of by-passing strong typing and encapsulation. The goal is to store scoped data in a general, but managed way, independent of protocols and presentation technology. Data stored within a scope is by nature shared, can still be structured, and is inherently different than one-off parameters passed to a method.
Context Object Pattern was first introduced in the Core J2EE Patterns 2nd Ed. The 'Context' part refers to the fact that the Object holds data in the Context of a scope
(such as application/session/request/conversation/flash
).
Its purpose is to decouple, as much as possible, application data and logic from protocol/presentation-technology- specific classes such as HttpSession
and HttpRequest
.
Pattern Implementation
Under Context Object, data intended for application/session/request/other scope is not put directly into ServletContext
/HttpSession
/HttpRequest
/other protocol-specific class. Instead, the data is stored in a POJO wrapper class, that then sits in the ServletRequest
/HttpSession
/HttpRequest
/other.
The Context Object may store the data in a map, but it doesn't need to - it can store the data in any structure/format relevant to the program.
An application may use one Context Object class per scope, or several classes which split the data in an orderly fashion, avoiding excessive Class bloat and promoting separation of concerns.
The Context Object is used by the frontmost presentation classes (Views, Front Controllers, Dispatchers). These presentation client objects call contextObject.get to retrieve stored scoped data and contextObject.put to store scoped context data.
It is not passed into business/integration logic. It is not used as a means of passing a multitude of parameters into business objects, by-passing strong typing. The Business and Integration Tiers are fronted by Business Delegates, Application Services and/or Session Facades which use specific strongly-typed parameters.
Pattern Benefits
- Testability: Unit tests only need to mock a simple POJO, rather than a protocol-specific complex server class, such as
ServletContext
orHttpRequest
- Flexibility & Reusability: The core of the application works independently of the thin protocol-specific 'presentation' layer of classes. This means that an application can more easily change or add protocols or presentation technology (e.g. HTML/HTTP/Servlet and WAP/Servlet and XML/SOAP/HTTP/EJB and HTML/HTTP/JSF).
Comments
- Is an historical pattern
- One could argue that dependency injection frameworks, such as CDI, Guice, Spring, Seam, & others give scope storage already implemented in a protocol-independent way. i.e. that all of the scopes are implemented as Context Objects already, meaning that the developer is less compelled to create additional Context Objects. That doesn't negate the pattern - it means the CDI framework already supports the pattern.
- If incorrectly implemented, one can end up with the "Pass Around Ginormous Context Objects Throughout The Application" anti-pattern
Quoting KaptajnKold: I think you got it. However, I also think it is more of an anti-pattern to be avoided. See why here.
Your comments refer to the misimplemented version of Context Object. Context Object itself is not an anti-pattern.
Solution 2:
A context object provides access to shared data and functions.
It can be an elegant and flexible substitute for:
- globals
- singletons
- long parameter lists
The ACCU provides a more detailed description.
If you want a real world example of the context pattern in Java, check the Google Android API's.
You need to be mindful of your dependency graph when using the context pattern. (This is the reason KaptajnKold calls it an anti-pattern.)
To limit unnecessary dependencies, use different contexts for different purposes. Keep your contexts as simple as possible and use composition or inheritance to add complexity when needed.