[Tutor] Null Object Design Pattern Question [sentinels and
Minesweeper]
Tim Johnson
tim at johnsons-web.com
Mon Jun 14 18:56:58 EDT 2004
Thanks to all for the pointers and examples on the topic.
I believe you've given me a good handle on the NOP.
cheers
tim
* Danny Yoo <dyoo at hkn.eecs.berkeley.edu> [040614 00:20]:
>
> On Sun, 13 Jun 2004, [ISO-8859-1] Gon?alo Rodrigues wrote:
>
> > >I have been looking at
> > >
> > >http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205
> > >
> > >which has an example of using a Null() object.
> > >
> > >Unfortunately, I'm having a problem wrapping my brain around the
> > >usefulness of this object compared to just using None.
> > >
> > >Does anyone have some further examples of the 'superiority' of this
> > >approach over *None*.
> >
> > Imagine a null object as a kind of sink: it responds to all messages
> > without barfing.
>
>
> Hi Tim,
>
> If you're familiar with the use of a "sentinel" to simplify a program's
> logic, then you can think of a "Null Object" as an OOP analogy to a
> sentinel.
>
>
> I like using concrete examples, and one of the nice examples where
> sentinels come in really handy is something like a Minesweeper-like game
> program. Here's a quick link to one:
>
> http://www.programming-challenges.com/pg.php?page=downloadproblem&probid=110102&format=html
>
> In the game of Minesweeper, we might want to report the number of mines
> adjacent to a space. For example, if we have:
>
> *...
> ....
> .*..
> ....
>
> we'd like to get back something like:
>
> *100
> 2210
> 1*10
> 1110
>
>
> If we represent a minefield as a list of rows, like this:
>
> minefield = ['*...',
> '....',
> '.*..',
> '....']
>
> and if we wanted to get the number of mines at an
> arbitrary row and col, we might write something like:
>
> ###
> def countMines(row, col):
> """Returns the number of mines around position(row, col)."""
> count = 0
> for i in [-1, 0, 1]:
> for j in [-1, 0, 1]:
> if minefield[row + i][col +j] == '*':
> count += 1
> return count
> ###
>
>
> The only problem is that this code doesn't work. *grin*
>
> ###
> >>> countMines(3, 3)
> Traceback (most recent call last):
> File "<stdin>", line 1, in ?
> File "<stdin>", line 6, in countMines
> IndexError: string index out of range
> ###
>
> The problem is that there's this special logic around the edges of the
> board, so our beautiful countMines() function malfunctions around the
> board edges.
>
>
> One way to fix countMines() is to add special-case logic into countMines()
> for counting mines around the edges of the board, maybe something like:
>
> ###
> if not (0 <= row + i < 4): continue
> ###
>
>
> But there's another way of fixing the problem, and it involves using
> sentinels. In effect, we take something like:
>
> *...
> ....
> .*..
> ....
>
>
> and wrap a sentinel border of '=' characters around the whole game board:
>
> ======
> =*...=
> =....=
> =.*..=
> =....=
> ======
>
> With this sentinel border, the code doesn't have to worry about the edge
> of the board so much. If I ask for the number of mines on the
> bottom-right corner --- countMines(4, 4) --- then we're perfectly ok,
> since we don't go off the board. Does this make sense?
>
>
> Null Objects perform a similar function: they are "sentinels" that allow
> us to simplify our main code, so that we don't have to worry so much about
> the special case of handling a reference to None.
>
>
> Hope this helps!
>
>
> _______________________________________________
> Tutor maillist - Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
--
Tim Johnson <tim at johnsons-web.com>
http://www.alaska-internet-solutions.com
More information about the Tutor
mailing list