Instances of using the NullObject design pattern. (...from those who HaveThisPattern.)
A simple example of NullObject:
class NullOutputStream extends OutputStream { public void write(int b) { // Do nothing } } class NullPrintStream extends PrintStream { public NullPrintStream() { super(new NullOutputStream()); } } class Application { private PrintStream debugout; public Application(PrintStream debugout) { this.debugout = debugout; } public void go() { int sum = 0; for (int i = 0; i < 10; i++) { sum += i; debugout.println("i = " + i); } System.out.println("sum = " + sum); } }--HiroshiYuki.
I HaveThisPattern: In a system that exchanged messages between disconnected systems via email, I had a "Protocol" object that handled the general algorithm calling an "email system driver" object to send and receive email messages via whichever email protocol was in use on the box. I had drivers for MAPI, VIM, and others.
However, the most popular and useful protocol for local testing was the "Null Object" protocol: After staging files in a (configurable) send directory and calling the "send email" function, the Null Object would return successfully without doing anything. When the receiving side called the Null Object "receive email" function, it would also do nothing, but with proper configuration of the receive directory, the receiving system would find the files already in its receive staging directory anyway (via shared network drives, for example).
Performance is often a non-issue: The cost of a C++ virtual function call is trivial relative to the cost of several relational database operations and the creation of a disk file or two.
The main benefit of this pattern is simplification of the calling code: My "Protocol" object did NOT have to check for a NULL pointer before all of its calls to the email driver object. It knew that it could always safely call the email driver, even when the function of the email driver was to do nothing. -- JeffGrigg
The ImmutableList example in the ImmutableCollection JavaIdiom also uses this pattern to avoid littering the code with checks for null references.
Another example: the Unix bit-bucket /dev/null is a NullObject (MSDOS has something similar). It looks and behaves much like a normal filename in that it can be open, read, written and closed, but anything written to it is thrown away and reads from it always return end-of-file. It can be used to dispose of progress reports that no-one is interested in. Rather than:
if (wantProgressReports) if (pProgressStream != NULL) (*pProgressStream) << "Read " << n << " items.\n";or the more explicit:
if (wantProgressReports) progressStream << "Read " << n << " items.\n";you bind the progressStream to /dev/null, write the output and let the stream ignore it. It leads to fewer "if" statements, and often faster code (since the polymorphic dispatch is needed anyway). It can avoid having to pass around special flags like wantProgressReports.
In C++ there usually isn't much confusion between a progressStream that is bound to /dev/null, and a NULL pointer. It is very rare to need to test if the progressStream is, in fact, bound to /dev/null - the intent of the pattern is to avoid such tests. -- DaveHarris
''Thank you, Dave, for providing such a good example. I got the feeling as I read this page that there are 2 completely different concepts being confused because of their similar names. Of course, to completely confuse the situation, the use of values like nil/null are examples of the use of the NullObject pattern at a fundamental level. References/pointers can hold this special value to avoid the need to carry round additional boolean flags with every reference that might not have a valid value. nil/NULL can respond to every method that a valid value could, but the response is to throw an exception/die. --DaveWhipp.''
This is a bit C++ specific, but can anyone think of an efficient way to implement:
DebugStream(level) << slowFn() << endl;in such a way that slowFn() is not called when DebugStream(level) returns some form of null object (for rejected debug output). Maybe I could use the && operator and find someway to hijack the short-circuit evaluation?
You are kind of screwed. You could do something like this:
#define dbg_level( N )if ( dbg::System.LEVEL >= N ) dbg::coutBut that wouldn't work for embedded calls to dbg_level. The problem is that while you can make DebugStream( level ) return a null object, you cannot do anything for slowFn() if you do not control it. This includes any stream manipulators such as those that do base to base conversion, allocate string storage, and so on. While the macros are ugly, at least you can remove slowFn() with conditional compilation.
DBG_Trace( 1, dbg::cout << slowFn() << std::endl; );Or something like that. -- AnonymousDonor
I think that what you may want is for slowFn() to return a LazyObject. That way the NullObject that DebugStream returns can ignore its input and just return itself. All you have to do is implement a "<<" operator that takes LazyObjects (actually you'll need a bunch of different flavored LazyObjects and a bunch of "<<" operators to go with them). LazyObjects are a way for functions to return something really quickly without actually doing any work. When the LazyObject is evaluated it performs the needed calculation on the spot, caches the result for use the next time the evaluation is called for, and returns it. -- PhilGoodwin
I've been thinking about a kind of lazy collection as a null object with some non-trivial behaviour. It is used like:
container := container add: item.and implemented with 2 classes:
EmptyContainer>>add: anItem ^NonEmptyContainer with: anItem EmptyContainer>>size ^0 NonEmptyContainer>>initialize wrappedCollection := OrderedCollection new. NonEmptyContainer>>add: anItem wrappedCollection add: anItem. ^self NonEmptyContainer>>size ^wrappedCollection sizeThe EmptyContainer is a kind of NullObject. You can also see this as an example of LazyEvaluation. You don't have to wrap a standard collection - you could inherit from it instead. This should lead to something which is faster, and less memory-hungary, then a plain collection. The overhead is pretty much just the assignment on #add:. -- DaveHarris
This is exactly how I implemented the ImmutableList, that I used as an example of an ImmutableCollection! --NatPryce
Here only the EmptyContainer is immutable (null objects should always be immutable...) the NonEmptyContainer is not immutable. -- DaveHarris
I use this class frequently when testing servlet methods:
public class NullHttpServletRequest implements HttpServletRequest { public Hashtable parameters = new Hashtable(); public void setParameter(String key, String value) { parameters.put(key, value); } public String getParameter(String key){ return (String)this.parameters.get(key); } public Enumeration getParameterNames(){ return this.parameters.elements(); } public Cookie[] getCookies() {return null;} public String getMethod(){return null;} public String getRequestURI(){return null;} public String getServletPath(){return null;} public String getPathInfo(){return null;} public String getPathTranslated(){return null;} public String getQueryString(){return null;} public String getRemoteUser(){return null;} public String getAuthType(){return null;} public String getHeader(String name){return null;} public int getIntHeader(String name){return 0;} public long getDateHeader(String name){return 0;} public Enumeration getHeaderNames(){return null;} public HttpSession getSession(boolean create){return null;} public String getRequestedSessionId(){return null;} public boolean isRequestedSessionIdValid(){return false;} public boolean isRequestedSessionIdFromCookie(){return false;} public boolean isRequestedSessionIdFromUrl(){return false;} public int getContentLength(){return 0;} public String getContentType(){return null;} public String getProtocol(){return null;} public String getScheme(){return null;} public String getServerName(){return null;} public int getServerPort(){return 0;} public String getRemoteAddr(){return null;} public String getRemoteHost(){return null;} public String getRealPath(String path){return null;} public ServletInputStream getInputStream() throws IOException{return null;} public String[] getParameterValues(String name){return null;} public Enumeration getAttributeNames(){return null;} public Object getAttribute(String name){return null;} public HttpSession getSession(){return null;} public BufferedReader getReader() throws IOException{return null;} public String getCharacterEncoding(){return null;} public void setAttribute(String name, Object o) {} public boolean isRequestedSessionIdFromURL() {return false;} }I think this is a NullObject... maybe it's something else? --Tom Copeland
It's HUGE! That's what it is!
Yeah, it's a pain to create empty implementations for those large interfaces. I would have done it with a throw new RuntimeException("missing") as the body of the methods, though.
But then it wouldn't be using the NullObject pattern!
Well, if some of the methods did their default behaviour, and the ones that throw aren't supposed to be called, it would be okay, wouldn't it?
When you return null for getScheme, getProtocol, etc. you are in effect just pushing the problem one step further. Try returning "" (String's buildin NullObject) for strings and new <Class>[0] (Array's buildin NullObject) for arrays -- NullObjectsReturnNullObjects?. When you return null for such objects, it is almost alway an error situation, and in that case, throwing an exception is much cleaner.
I have something similar which I use in my testing. I call it MockServletRequest?, though, because I don't think it's the same sort of thing as a NullObject; I think of it (perhaps improperly) as being a MockObject. Each method throws a runtime exception; I subclass it as necessary in my unit tests and override whichever methods I expect to be called. --BrettNeumeier
Here's a Python version of a NullObject/ShuntPattern combination which I use when the program needs a ComplexDataSetupForAutomatedTests:
class NullShunt?: def __call__(self, *args, **kwargs): return self.__class__() def __getitem__(self, key): return self.__class__() def __nonzero__(self): return 0 def __str__(self): return '' def __getattr__(self, name): setattr(self, name, MockNull?()) return getattr(self, name)The nice trick here is in __getattr__. This allows assignments like "client.db.config.TRACKER_WEB = 'BASE/'" or "client.db.issue.get = lambda: 1", with only client defined.
Also see NullObjectAndVisitor. Also see JavaNullProxy.