1.单体模式的宗旨
单体模式的宗旨在于确保某个类只有唯一的一个实例,并且为该类提供一个全局的访问点。
当我们开发项目时,经常会发现一些类需要只有一个实例,比如:Window Manager,Print Spooler,对数据库引擎的唯一访问点等等。单体模式被GoF归于创建型的模式,但我认为它应归位责任型的模式,因为单体模式的价值在于将一个类的职责集中在唯一的一个单体对象之中。
2.单体模式的实现
单体模式的实现有很多种,每种都有自身的优点和缺点,但是宗旨都是确保单体的唯一。由于static关键字的“天生资质”,注定了它与单体模式的“姻缘”。下面罗列出几种实现方法,假设的场景都是:将PrintSpooler类设计为单体,现在就让我们一起来比较一下吧!
a.通过Exception机制
首先为了程序更加清晰,我们自己定义一个异常类SingletonException:
- public class SingletonException extends RuntimeException {
- public SingletonException() {
- super();
- }
- public SingletonException(String s) {
- super(s);
- }
- }
接下来就是单体模式关键的部分:
- public class PrintSpooler {
- static boolean instance_flag=false;
- public PrintSpooler() throws SingletonException {
- if (instance_flag)
- throw new SingletonException("Only one spooler allowed");
- else
- instance_flag = true;
- System.out.println("spooler opened");
- }
- public void finalize() {
- instance_flag = false;
- }
- }
现在为止,PrintSpooler单体设计已经完成,让我们看看如何使用它:
- public class singleSpooler {
- static public void main(String argv[]) {
- PrintSpooler pr1, pr2;
- System.out.println("Opening one spooler");
- try {
- pr1 = new PrintSpooler();
- } catch (SingletonException e) {
- System.out.println(e.getMessage());
- }
- System.out.println("Opening two spoolers");
- try {
- pr2 = new PrintSpooler();
- } catch (SingletonException e) {
- System.out.println(e.getMessage());
- }
- }
- }
运行结果如下:
Opening one spooler
printer opened
Opening two spoolers
Only one spooler allowed
通过结果我们可以很清楚的发现我们程序完成了设计的意图确保了实例的唯一,但是这种方法的缺点就是我们必须把调用代码包在try-catch块之中,使简单的调用变得太复杂了,对于具有“懒惰”美德的程序员来说,这样有一些太笨了......
b.通过final和static
看看下面的解决方案:
- final class PrintSpooler {
- static public void print(String s) {
- System.out.println(s);
- }
- }
如何使用:
- public class staticPrint {
- public static void main(String argv[]) {
- Printer.print("here it is");
- }
- }
将PrintSpooler设计为final约束的,这样它就不能被其他类所扩张(继承),通过static的特性确保内存中实例的唯一,直接通过类名调用方法。不过这看上去更像一个工具类了啊,不错,Java的Math库正是采取这种设计的,当然这种设计的缺点就是我们对PrintSpooler的约束过于强大了。
c.GoF的解决方案
下面让我们看看最流行的解决方案吧,当然也是我们在项目中用到的最广泛的GoF的那本“设计模式圣经”里面所描述的:
- public class PrintSpooler {
- private PrintSpooler(){}
- private static PrintSpooler instance = new PrintSpooler();
- public static PrintSpooler getInstance() {
- return instance;
- }
- }
神奇吗?把构造函数设为private的,这样的话外部就不能实例化PrintSpooler类,只有自己本身能够实例化自己,然后通过静态方法getInstance()返回这个实例从而提供唯一的访问点。如果你试着运行这行代码:
PrintSpooler p = new PrintSpooler();
^_^,编译器是不会放过你的!那么我们如何使用PrintSpooler呢?很简单,我们敲下这行代码就可以了:
PrintSpooler p = PrintSpooler.getInstance();
这个解决方案还有另外一种变形,就是用到Lazy-initialize:
- public class PrintSpooler {
- private PrintSpooler(){}
- private static PrintSpooler instance = null;
- public static synchronized PrintSpooler getInstance() {
- if(instance == null)
- instance = new PrintSpooler();
- return instance;
- }
- }
这里有两个问题需要解决:为什么需要 Lazy-initialize?它是什么 ?
那里冒出的 synchronized ?
首先,因为有时候单体类在实例化时所需的数据只有在运行时通过计算才能获得,所以我们必须延迟实例化,所以也就有了先前的惰性初始化(Lazy-initialize)--第一次调用时进行初始化。
其次,考虑的线程安全的因素,如果一个线程发现instance==null而去实例化PrintSpooler,且此时PrintSpooler还未实例化完毕。与此同时另一线程也检查instance,结果为instance==null,所以也去实例化PrintSpooler了,现在PrintSpooler有了两个实例,不再是单体了。为了防止上面的情况发生,可以用synchronized提供的锁机制,所以就冒出了synchronized!
3.需要注意的问题
有时在某些情况下,使用Singleton并不能达到Singleton的目的,如有多个Singleton对象同时被不同的类装入器装载;在EJB这样的分布式系统中使用也要注意这种情况,因为EJB是跨服务器和JVM的。所以在EJB中,单体模式就失效了!
4.再罗嗦一些......
在工厂模式中的类装载器(Class Loader)就是一个单体,J2EE设计模式中的ServiceLocator也是一个单体...我们仔细观察会发现我们的项目中在不知不觉用到好多的单体,其实单体模式的实现并没有难点,真正的难点在于在系统中如何识别单体和不滥用单体,这种敏感性只有不断的实践中才能锻炼出来,所以用好Singleton是非常不容易的事情......
分享到:
相关推荐
Java常用设计模式(SingleTon、FactoryMethod、AbstractFactory)
简单的单例模式举例Singleton 分为恶汉式 懒汉式
.NET c# 单体模式(Singleton)
Singleton模式包含的角色只有一个,就是Singleton。Singleton拥有一个私有构造函数,确保用户无法通过new直接实例化它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance()...
Singleton模式: 确保一个类只有唯一的一个实例。 Singleton主要用于对象的创建,这意味着,如果某个类采用了Singleton模式,则在这个类被创建后,它将有且仅有一个实例可供访问。很多时候我们都会需要Singleton...
C++完美实现Singleton模式
设计模式-Singleton与Factory
单例设计模式Singleton1
单例模式 Singleton 单例模式线程安全问题和拓展
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个...
23种设计模式之三(创建型模式)Singleton模式
李建忠面向对象设计模式视频精讲:Singleton 单件(创建型模式)
单例模式(Singleton)
用VC实现的singleton 模式 在VS03,VC6.0下编译通过
此示例展示了Qml 的单例模式(类似全局对象,只生成一次实例,可全局使用) surfsky.cnblogs.com
1、策略模式STRATEGY PATTERN 2、代理模式PROXY PATTERN 3、单例模式SINGLETON PATTERN 4、多例模式MULTITION PATTERN 5、工厂方法模式FACTORY METHOD PATTERN 6、抽象工厂模式ABSTRACT FACTORY ...24、备忘录模式
设计模式C++学习之单例模式(Singleton)
java Singleton单例模式 java Singleton单例模式
最简单的设计模式学习Singleton模式