Skip to content

Instantly share code, notes, and snippets.

@ngerakines
Created September 23, 2009 07:12
Show Gist options
  • Select an option

  • Save ngerakines/191804 to your computer and use it in GitHub Desktop.

Select an option

Save ngerakines/191804 to your computer and use it in GitHub Desktop.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<title>Game Programming Patterns / Singleton</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="jquery-1.3.2.min.js" type="text/javascript"></script>
</head>
<body>
<div class="nav">
<h1><a href="index.html">Navigation</a></h1>
<ul>
<li>Getting Started
<ul>
<li><a href="introduction.html">Introduction</a></li>
<li>Working with Patterns</li>
</ul>
</li>
<li>Design Patterns Revisited</li>
<ul>
<li>Decorator</li>
<li>Prototype</li>
<li><a href="singleton.html">Singleton</a></li>
<li>Flyweight</li>
<li>Command</li>
<li>Observer</li>
<li>State</li>
<li>Strategy</li>
</ul>
<li>Game Programming Patterns
<ul>
<li>Sequencing Patterns
<ul>
<li>Game Loop</li>
<li>Update Method</li>
<li>Double Buffer</li>
<li>Dead Pool</li>
</ul>
</li>
<li>Behaving Patterns
<ul>
<li>Split Representation</li>
<li>Metaclass</li>
<li>Sandbox Method</li>
<li>Context Parameter</li>
<li>Virtual Machine</li>
</ul>
</li>
<li>Communicating Patterns
<ul>
<li>Service</li>
<li>Message Queue</li>
<li>Blackboard</li>
<li>Area Effect</li>
<li>Collision</li>
</ul>
</li>
<li>Optimizing Patterns
<ul>
<li><a href="object-pool.html">Object Pool</a></li>
<li>Structure of Arrays</li>
<li>Dirty Bits</li>
</ul>
</li>
</ul>
</li>
</ul>
</div><div id="content">
<h1 class="book">Game Programming Patterns</h1>
<h1>Singleton</h1>
<div class="feedback">
<p>You're reading a work-in-progress. If you'd like to help
make it better, please give me some feedback by emailing.
The address is my name (robert) at stuffwithstuff.com.</p>
<p><a href="#" class="hide">hide</a></p>
<p>Thank you!</p>
</div>
<script type="text/javascript">
/* <![CDATA[ */
$(document).ready(function()
{
$("a.hide").click(function(event) {
$(this).parent().parent().hide();
event.preventDefault();
});
});
/* ]]> */
</script>
<p>This chapter is an anomaly. Every other chapter in this book shows
you how to use a design pattern. This one shows you how <em>not</em> to use
one.</p>
<p>Despite noble intentions, the <a class="gof-pattern"
href="http://c2.com/cgi/wiki?SingletonPattern">Singleton</a> pattern
described by the Gang of Four usually does more harm than good. While
they stress that the pattern should be used sparingly, game
programmers struggling with object-oriented programming took it and
ran with it. Like any pattern, using it where it doesn&#x2019;t belong is
about as helpful as treating a bullet wound with a splint. Since it&#x2019;s
so over-used, most of this chapter will be about <em>avoiding</em>
Singletons, but first, let&#x2019;s go over the pattern itself.</p>
<h2>The Singleton Pattern</h2>
<p><em>Design Patterns</em> summarizes Singleton like this:</p>
<blockquote>
<p>Ensure a class has one instance, and provide a global point of
access to it.</p>
</blockquote>
<p>We&#x2019;ll split that at &ldquo;and&rdquo; and consider each half
separately.</p>
<h3>Restricting a Class To One Instance</h3>
<p>There are times when a class cannot perform correctly if there is more
than one instance of it. The common case is when the class interacts
with an external system that maintains its own global state.</p>
<p>Consider a class that wraps an underlying file system API. Because
file operations can take a while to complete, our class performs
operations asynchronously. This means multiple operations can be
running concurrently, so they must be coordinated with each other. If
we start one call to create a file, and another one to delete that
same file, our wrapper needs to be aware of both to make sure they
don&#x2019;t interfere with each other.</p>
<p>To do this, a call into our wrapper needs to have access to every
previous operation. If users could freely create instances of our
class, one instance has no way of knowing about operations that other
instances started. Enter the Singleton. It provides a way for a class
to ensure at compile time that there is only a single instance of the
class.</p>
<h3>Providing a Global Point of Access</h3>
<p>Several different systems in the game will use our file system
wrapper: logging, content loading, game state saving, etc. If those
systems can&#x2019;t create their own instances of our file system wrapper,
how do they get ahold of one?</p>
<p>Singleton provides a solution to this too. In addition to creating the
single instance, it also provides a globally-available method to get
it. This way, anyone
h1, h2, h3, h4, p, blockquote, code, ul, ol, img {
margin: 0;
}
body {
/* background-image: url("grid.gif"); */
margin: 40px 20px;
line-height: 20px;
}
#content h1 {
color: #000;
font: normal 24px/40px 'Century Schoolbook', Georgia, serif;
margin-bottom: 20px;
padding: 0 0 5px 0;
border-bottom: solid 5px #ddd;
width: 560px;
}
#content h1.book {
color: #777;
font: normal 18px/20px 'Century Schoolbook', Georgia, serif;
padding-bottom: 10px;
width: 560px;
border: none;
}
h2 {
color: #05f;
font: normal 18px/20px 'Century Schoolbook', Georgia, serif;
padding: 10px 0 10px 0;
width: 560px;
}
h3 {
color: #05f;
font: italic 16px/20px 'Century Schoolbook', Georgia, serif;
padding: 0 0 0 20px;
width: 560px;
}
h4 {
color: #777;
font: italic 15px/20px 'Century Schoolbook', Georgia, serif;
padding: 0 0 0 20px;
width: 560px;
}
p {
margin-bottom: 20px;
padding: 0;
}
p, li {
color: #333;
font: normal 15px/20px 'Century Schoolbook', Georgia, serif;
}
li {
/* lighten the bullets. this will also have the intended side-
effect of making it apparent when markdown fails to wrap a
list item's text in a <p>, which screws up the formatting. */
color: #777;
}
ul, ol {
padding: 0 0 0 20px;
}
a {
color: #05f;
text-decoration: none;
}
img {
padding: 0 0 16px 20px;
}
blockquote {
width: 460px;
background: #f4f4f4;
margin: -10px 0 10px 40px;
padding: 8px 20px 12px 20px;
}
blockquote p {
font-style: italic;
color: #777;
}
blockquote p {
margin-bottom: 0;
}
blockquote p + p {
margin-top: 20px;
}
/* make room for the sidebar */
#content > p {
margin-left: 20px;
width: 540px;
}
#content > ol,
#content > ul {
margin-left: 20px;
width: 520px;
}
#content > pre {
margin-left: 20px;
width: 500px;
}
pre {
color: #777;
font: normal 12px/20px 'Bitstream Vera Sans Mono', Monaco, Consolas, monospace;
background: #f4f4f4;
margin: -10px 0 10px 0;
padding: 8px 20px 12px 20px;
}
code {
color: #777;
font: normal 12px 'Bitstream Vera Sans Mono', Monaco, Consolas, monospace;
}
#content {
margin-left: 240px;
width: 800px;
}
/* sidebar */
.sidebar {
float: right;
clear: right;
}
.sidebar p {
color: #777;
font: italic 13px/20px 'Century Schoolbook', Georgia, serif;
width: 200px;
}
.sidebar em {
font-style: normal;
}
/* nav bar */
.nav {
float: left;
width: 180px;
margin-top: 100px;
padding: 20px 20px 20px 20px;
background: #f4f4f4;
}
.nav h1 {
font: normal 16px/20px 'Century Schoolbook', Georgia, serif;
color: #777;
}
.nav li {
color: #777;
padding: 0;
font: normal 13px/20px 'Century Schoolbook', Georgia, serif;
}
/* notes to myself */
p.note {
display: none;
/*
color: #d00;
font: normal 12px/20px 'Bitstream Vera Sans Mono', Monaco, Consolas, monospace;
*/
}
/* ascii art diagrams */
pre.diagram {
background: #efe;
color: #080;
font: normal 10px/10px 'Bitstream Vera Sans Mono', Monaco, Consolas, monospace;
}
/* pattern links */
a.pattern,
a.gof-pattern {
border-bottom: solid 1px #acf;
}
a.pattern:after,
a.gof-pattern:after {
}
a.pattern:after {
content: "\00A0\2192";
}
a.gof-pattern:after {
content: "\00A0(GoF)";
}
/* feedback on content */
.feedback-btn {
float: right;
margin: -26px 240px 0 0;
font: normal 11px Verdana, sans-serif;
}
.feedback-btn a {
color: #d80;
padding: 3px;
text-decoration: underline;
}
.feedback-btn a:hover {
background: #fec;
}
.feedback-box {
margin: 0 0 20px 20px;
padding: 5px;
width: 530px;
background: #fec;
}
.feedback-box p {
font: normal 13px Verdana, sans-serif;
color: #a60;
padding-bottom: 5px;
}
/* feedback box */
.feedback {
margin-right: 240px;
background: #fec;
padding: 19px 20px 1px 20px;
margin-bottom: 20px;
}
.feedback p {
color: #a60;
}
a.hide {
float: right;
font: normal 11px Verdana, sans-serif;
color: #d80;
padding: 3px;
text-decoration: underline;
}
.feedback a {
color: #630;
text-decoration: underline;
}
/* footer */
p.footer {
text-align: center;
font-style: italic;
margin: 20px 0 20px 0;
padding: 15px 0 0 0;
border-top: solid 5px #ddd;
width: 560px;
}
/* thanks */
p.thanks {
margin: 40px auto;
padding: 20px;
width: 400px;
background: #cfc;
color: #080;
}
/* outline */
.outline-note {
margin-right: 240px;
background: #fdf;
padding: 19px 20px 1px 20px;
margin-bottom: 20px;
}
.outline-note p,
.outline h2,
.outline h3,
.outline a,
a.outline {
color: #a0a;
}
a.outline {
font-style: italic;
}
a.outline:before {
content: "("
}
a.outline:after %7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment