现在的位置: 首页 > 综合 > 正文

java singleton design pattern

2013年10月15日 ⁄ 综合 ⁄ 共 6477字 ⁄ 字号 评论关闭

from: http://www.javacoffeebreak.com/articles/designpatterns/index.html

For
those who haven't heard of design patterns before, or who are familiar
with the term but not its meaning, a design pattern is a template for
software development. The purpose of the template is to define a particular behavior or technique that
can be used as a building block for the construction of software - to
solve universal problems that commonly face developers. Think
of design code as a way of passing on some nifty piece of advice, just
like your mother used to give. "Never wear your socks for more than
one day" might be an old family adage, passed down from generation
to generation. It's common sense solutions that are passed on to others.
Consider a design pattern as a useful piece of advice for
designing software.

Design patterns out of the way, let's look at the singleton. By now,
you're probably wondering what a singleton is - isn't jargon terrible? A
singleton is an object that cannot be instantiated. At first, that might
seem counterintuitive - after all, we need an instance of an object
before we can use it. Well yes a singleton can be created, but it can't
be instantiated by developers - meaning that the singleton class has
control over how it is created. The restriction on the singleton is that
there can be only one instance of a singleton created by the Java
Virtual Machine (JVM) - by prevent direct instantiation we can ensure
that developers don't create a second copy.

So why would this be useful? Often in designing a system, we want to
control how an object is used, and prevent others (ourselves included) from making copies
of it or creating new instances. For example, a central configuration
object that stores setup information should have one and one only
instance - a global copy accessible from any part of the application,
including any threads that are running. Creating a new configuration
object and using it would be fairly useless, as other parts of the
application might be looking at the old configuration object, and
changes to application settings wouldn't always be acted upon. I'm sure
you can think of a other situations where a singleton would be useful -
perhaps you've even used one before without giving it a name. It's a
common enough design criteria (not used everyday, but you'll come across
it from time to time). The singleton pattern can be applied in any
language, but since we're all Java programmers here (if you're not,
shame!) let's look at how to implement the pattern using Java.

Preventing direct instantiation

We all know how objects are instantiated right? Maybe not everyone? Let's go
through a quick refresher.

Objects are instantiated by using the new
keyword. The new
keyword allows you to create a new instance of an object, and to specify
parameters to the class's constructor. You can specify no parameters, in
which case the blank constructor (also known as the default
constructor) is invoked. Constructors can have access modifiers, like
public and private, which allow you to control which classes have access
to a constructor. So to prevent direct instantiation, we create a
private default constructor, so that other classes can't create a new
instance.

We'll start with the class definition, for a SingletonObject class.
Next, we provide a default constructor that is marked as private. No
actual code needs to be written, but you're free to add some
initialization code if you'd like. 

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}
}

So far so good. But unless we add some further code, there'll be
absolutely no way to use the class. We want to prevent direct
instantiation, but we still need to allow a way to get a reference to an
instance of the singleton object.

Getting an instance of the singleton

We need to provide an accessor method, that returns an instance of
the SingletonObject class but doesn't allow more than one copy to be
accessed. We can manually instantiate an object, but we need to keep a
reference to the singleton so that subsequent calls to the accessor
method can return the singleton (rather than creating a new one). To do
this, provide a public static method called getSingletonObject(), and
store a copy of the singleton in a private member variable.

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}

public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}

private static SingletonObject ref;
}

So far, so good. When first called, the getSingletonObject() method
creates a singleton instance, assigns it to a member variable, and
returns the singleton. Subsequent calls will return the same singleton,
and all is well with the world. You could extend the functionality of
the singleton object by adding new methods, to perform the types of
tasks your singleton needs. So the singleton is done, right? Well
almost.....

Preventing thread problems with your singleton

We need to make sure that threads calling the getSingletonObject()
method don't cause problems, so it's advisable to mark the method as
synchronized. This prevents two threads from calling the
getSingletonObject() method at the same time. If one thread entered the
method just after the other, you could end up calling the
SingletonObject constructor twice and returning different values. To
change the method, just add the synchronized
keyword as
follows to the method declaration :-

public static synchronized
SingletonObject getSingletonObject()

Are we finished yet?

There, finished. A singleton object that guarantees one instance of
the class, and never more than one. Right? Well.... not quite. Where
there's a will, there's a way - it is still possible to evade all our
defensive programming and create more than one instance of the singleton
class defined above. Here's where most articles on singletons fall down,
because they forget about cloning. Examine the following code snippet,
which clones a singleton object.

public class Clone
{
public static void main(String args[])
throws Exception
{
// Get a singleton
SingletonObject obj =
SingletonObject.getSingletonObject();

// Buahahaha. Let's clone the object
SingletonObject clone =
(SingletonObject) obj.clone();
}
}

Okay, we're cheating a little here. There isn't a clone()
method defined in SingletonObject, but there is in the java.lang.Object
class which it is inherited from. By default, the clone()
method
is marked as protected, but if your SingletonObject extends another
class that does support cloning, it is possible to violate the design
principles of the singleton.  So, to be absolutely positively 100%
certain that a singleton really is a singleton, we must add a clone()
method of our own, and throw a CloneNotSupportedException
if anyone dares try!

Here's the final source code for a SingletonObject, which you can use
as a template for your own singletons.

public class SingletonObject
{
private SingletonObject()
{
// no code req'd
}

public static SingletonObject getSingletonObject()
{
if (ref == null)
// it's ok, we can call this constructor
ref = new SingletonObject();
return ref;
}

public Object clone()
throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
// that'll teach 'em
}

private static SingletonObject ref;
}

Summary

A singleton is an class that can be instantiated once, and only once.
This is a fairly unique property, but useful in a wide range of object
designs. Creating an implementation of the singleton pattern is fairly
straightforward - simple block off access to all constructors, provide a
static method for getting an instance of the singleton, and prevent
cloning.

【上篇】
【下篇】

抱歉!评论已关闭.