Skip to content
Skip to breadcrumbs
Skip to header menu
Skip to action menu
Skip to quick search
Quick Search
Browse
Pages
Blog
Labels
Attachments
Mail
Advanced
What’s New
Space Directory
Feed Builder
Keyboard Shortcuts
Confluence Gadgets
Log In
Sign Up
Dashboard
Groovy
Copy Page
You are not logged in. Any changes you make will be marked as
anonymous
. You may want to
Log In
if you already have an account. You can also
Sign Up
for a new account.
This page is being edited by
.
Paragraph
Paragraph
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Preformatted
Quote
Bold
Italic
Underline
More colours
Strikethrough
Subscript
Superscript
Monospace
Clear Formatting
Bullet list
Numbered list
Outdent
Indent
Align left
Align center
Align right
Link
Table
Insert
Insert Content
Image
Link
Attachment
Symbol
Emoticon
Wiki Markup
Horizontal rule
tinymce.confluence.insert_menu.macro_desc
Info
JIRA Issue
Status
Gallery
Tasklist
Table of Contents
Other Macros
Page Layout
No Layout
Two column (simple)
Two column (simple, left sidebar)
Two column (simple, right sidebar)
Three column (simple)
Two column
Two column (left sidebar)
Two column (right sidebar)
Three column
Three column (left and right sidebars)
Undo
Redo
Find/Replace
Keyboard Shortcuts Help
<p>The <a href="http://en.wikipedia.org/wiki/Null_Object_pattern">Null Object Pattern</a> involves using a special object place-marker object representing null. Typically, if you have a reference to null, you can't invoke <code>reference.field</code> or <code>reference.method()</code>. You receive the dreaded <code>NullPointerException</code>. The null object pattern uses a special object representing null, instead of using an actual <code>null</code>. This allows you to invoke field and method references on the null object. The result of using the null object should semantically be equivalent to <em>doing nothing</em>.</p> <h3>Simple Example</h3> <p>Suppose we have the following system:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Job { def salary } class Person { def name def Job job } def people = [ new Person(name:'Tom', job:new Job(salary:1000)), new Person(name:'Dick', job:new Job(salary:1200)), ] def biggestSalary = people.collect{ p -> p.job.salary }.max() println biggestSalary </pre></td></tr></table> <p>When run, this prints out <code>1200</code>. Suppose now that we now invoke:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> people << new Person(name:'Harry') </pre></td></tr></table> <p>If we now try to calculate <code>biggestSalary</code> again, we receive a null pointer exception.</p> <p>To overcome this problem, we can introduce a <code>NullJob</code> class and change the above statement to become:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class NullJob extends Job { def salary = 0 } people << new Person(name:'Harry', job:new NullJob()) biggestSalary = people.collect{ p -> p.job.salary }.max() println biggestSalary </pre></td></tr></table> <p>This works as we require but it's not always the best way to do this with Groovy. Groovy's safe-dereference operator (<code>?.</code>) operator and null aware closures often allow Groovy to avoid the need to create a special null object or null class. This is illustrated by examining a groovier way to write the above example:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> people << new Person(name:'Harry') biggestSalary = people.collect{ p -> p.job?.salary }.max() println biggestSalary </pre></td></tr></table> <p>Two things are going on here to allow this to work. First of all, <code>max()</code> is <em>'null aware'</em> so that <code>[300, null, 400].max() == 400</code>. Secondly, with the <code>?.</code> operator, an expression like <code>p?.job?.salary</code> will be equal to null if <code>salary</code> is equal to null, or if <code>job</code> is equal to null or if <code>p</code> is equal to null. You don't need to code a complex nested <code>if ... then ... else</code> to avoid a <code>NullPointerException</code>.</p> <h3>Tree Example</h3> <p>Consider the following example (inspired by <a href="http://wiki.rubygarden.org/Ruby/page/show/NullObjectPattern">this</a>) where we want to calculate size, cumulative sum and cumulative product of all the values in a tree structure.</p> <p>Our first attempt has special logic within the calculation methods to handle null values.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class NullHandlingTree { def left, right, value def size() { 1 + (left ? left.size() : 0) + (right ? right.size() : 0) } def sum() { value + (left ? left.sum() : 0) + (right ? right.sum() : 0) } def product() { value * (left ? left.product() : 1) * (right ? right.product() : 1) } } def root = new NullHandlingTree( value:2, left: new NullHandlingTree( value:3, right: new NullHandlingTree(value:4), left: new NullHandlingTree(value:5) ) ) println root.size() println root.sum() println root.product() </pre></td></tr></table> <p>If we introduce the null object pattern (here by defining the <code>NullTree</code> class), we can now simplify the logic in the <code>size()</code>, <code>sum()</code> and <code>product()</code> methods. These methods now much more clearly represent the logic for the normal (and now universal) case. Each of the methods within <code>NullTree</code> returns a value which represents doing nothing.</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> class Tree { def left = new NullTree(), right = new NullTree(), value def size() { 1 + left.size() + right.size() } def sum() { value + left.sum() + right.sum() } def product() { value * left.product() * right.product() } } class NullTree { def size() { 0 } def sum() { 0 } def product() { 1 } } def root = new Tree( value:2, left: new Tree( value:3, right: new Tree(value:4), left: new Tree(value:5) ) ) println root.size() println root.sum() println root.product() </pre></td></tr></table> <p>The result of running either of these examples is:</p> <table class="wysiwyg-macro" data-macro-name="code" style="background-image: url(/plugins/servlet/confluence/placeholder/macro-heading?definition=e2NvZGV9&locale=en_GB&version=2); background-repeat: no-repeat;" data-macro-body-type="PLAIN_TEXT"><tr><td class="wysiwyg-macro-body"><pre> 4 14 120 </pre></td></tr></table> <p>Note: a slight variation with the null object pattern is to combine it with the singleton pattern. So, we wouldn't write <code>new NullTree()</code> wherever we needed a null object as shown above. Instead we would have a single null object instance which we would place within our data structures as needed.</p>
Please type the word appearing in the picture.
Attachments
Labels
Location
Watch this page
< Edit
Preview >
Loading…
Save
Cancel
Next hint
search
attachments
weblink
advanced