JavaSE0014_设计模式之单例模式

DesignPattern (设计模式)

 

1.      设计模式

 

有23个经典的设计模式

 

NO.1单例模式(Singleton):表示一个类只会生成唯一的一个对象。

思考:怎样可以让一个类有且只有一个实例呢?

1) 先定义两个类:

public classSingletonTest

{}

class Singleton

{}

2) 如何生成唯一的一个实例,决定于类生成实例的过程。我们知道实例生成是通过调用构造方法来实现的,而且构造方法肯定会被调用的。因此我们就考虑以构造方法为入口寻求解决方法。如果我们不提供构造方法,则系统会提供一个默认的不带参数的构造方法,每new一次,就生成一个对象,不能保证唯一性。如果我们提供构造方法,如定义一个构造方法Singleton(){},则在生成对象的时候,会调用此构造方法。如果有两个new,调用两次此构造方法,会生成两个对象,还是不能保证唯一性。

 

public classSingletonTest

{}

class Singleton

{

        Singleton()

        {}

}

3) 不提供构造方法肯定是不行的,提供了也不行,但是我们要从有构造方法这方面介入。我们知道,如果我们把构造方法定义成私有的,则外部无法调用,无法在外部生成实例,这样想感觉会少很多实例。

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton = newSingleton();

}

}

class Singleton

{

        Private Singleton()

        {}

}

 

4) 上面程序编译错误,因为私有构造方法不能被外部调用,进而在外部new时,报错。

这样,我们就里我们的目标更近了,此时最多生成零个实例。试想,现在不能再利用new来生成实例了,因此考虑可以在类里边定义一个可以返回实例的方法,间接生成实例。

public classSingletonTest

{

        public static void main(String[] args)

        {
              

}

}

class Singleton

{

        Private Singleton()

        {}

 

        public Singleton getInstance()

{

       return new Singleton();

}

}

5)上面程序进入死循环,因为实例方法getInstance() 的调用必须要在外面new一个对象之后,才能用此对象调用。也就是说,在调用他之前,要先生成实例。而我们定义此方法的目的就是不用在外面new出来一个实例。因此不对。然后我们就想其他调用方法的途径,比如可以用类直接调用静态方法,因此可以把getInstance()定义为 static 的。

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton =Singleton.getInstance();

}

}

class Singleton

{

        Private Singleton()

        {}

 

        public static Singleton getInstance()

{

       return new Singleton();

}

}

5) 上面程序编译通过,但是还是不能保证单例。只是把实例的生成转移到类的里面了。没调用一次,就会new一个对象。这里,我们发现,没调用一次方法getInstance()就会new 一个对象。试想,如果我们可以在方法外面先生成一个对象,然后在调用方法getInstance()的时候,返回这个生成好的对象,是不是就可以保证只有一个实例呢?

 

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton =Singleton.getInstance();

}

}

class Singleton

{

        private Singleton singleton = newSingleton();   

        private Singleton()

        {}

 

        public static Singleton getInstance()

{

       return singleton;

}

}

6)此程序编译不通过,因为静态的方法只能访问静态变量。

单例模式(形式一)

*********************************************************

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton =Singleton.getInstance();

}

}

class Singleton

{

        private static Singleton singleton = newSingleton(); 

        private Singleton()

        {}

 

        public static Singleton getInstance()

{

       return singleton;

}

}

*********************************************************

6) 测试其是否真的为单例

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton =Singleton.getInstance();

               Singleton singleton1 =Singleton.getInstance();

               System.out.println(singleton ==singleton1);

 

}

}

class Singleton

{

        private static Singleton singleton = newSingleton(); 

        private Singleton()

        {}

 

        public static Singleton getInstance()

{

       return singleton;

}

}

7)

单例模式(形式二)

*********************************************************

public classSingletonTest

{

        public static void main(String[] args)

        {
               Singleton singleton =Singleton.getInstance();

}

}

class Singleton

{

        private static Singleton singleton;

        private Singleton()

        {}

        public static Singleton getInstance()

{

       If(singleton ==null){singleton = new Singleton();}

       return singleton;

}

}

*********************************************************

对于前面单例模式的两种实现方法,可以先认为相同。在学习多线程之后,会知道,第二种可能不再是单例模式。因此,第一种比较优良。

 

 

第二种实现在多线程时不能保证只生成一个对象

public static Singleton getInstance()

{

       If(singleton == null)

{

singleton = new Singleton();

}

       return singleton;

}

 

分析:假设有两个线程,当第一个线程进入if循环后,正要执行:singleton= new Singleton();

他时,这时CPU将程序转到另一个线程,这时由于还没有生成对象,那么他也进入到if模块中,这样,就会生成两个对象。

异常模拟:

[com.Class013/SingletonTest2.java]

 

对于单例模式(Singleton)来说,如果在getInstance()方法中生成Singleton实例则可能会产生同步问题,即可能会生成两个不同的对象。


所谓设计模式(Design Pattern),是为了满足对优秀、简单而且可重用的解决方案的需要。这就像我们在盖楼的时候,我们不会每次都从零开始来画图纸,而是参照某种已有的模式,然后在此基础上来设计它。而在面向对象程序设计中,“模式”是为了实现重用面向对象代码的一种方便做法。


根据“设计模式”的经典著作《Design Patterns:Elements of reusable Object-Oriented software》中所述,设计模式一般包含四个基本要素:
1.模式名称(pattern name):一个助记名,用几个词汇来描述模式的问题、解决方案以及效果。
2.问题(problem):描述了应该在何时使用模式。
3.解决问题的方案(solution):描述了设计的组成部分,它们之间的相互关系及各自的职责和协作方式。
4.效果(consequences):描述了模式应用的效果及使用模式应权衡的问题。

 

我们现在来考虑单子(Singleton)设计模式的需求背景。

 

在实际应用中,我们可能需要限制生成的对象个数只能为1个。比如,在开发图形应用的时候,在菜单栏上按下“帮助”菜单,将弹出一个帮助对话框,也就是生成了一个帮助对话框的实例,如果对话框已经出现,则即使再在菜单栏上按下“帮助”菜单,应用程序也不应该再生成新的对话框实例。这个时候,如果还是通过原来的用构造器来生成实例的方式,很难对其生成的实例个数进行控制。通过所谓的“单子设计模式”,可以实现这个功能。

单子设计模式的基本思路是在类的内部定义一个静态变量,当创建第一个实例时设置该变量。应用程序直接使用这个静态变量指向的实例就可以了。为了防止应用程序调用构造器来新建实例,必须限制构造器的访问,也就是将它的访问控制设置为“private”。


概括起来,要实现“单子设计模式”,可以利用下面的方式来完成:
创建一个类,满足:
构造器私有;
用一个私有、静态变量引用实例;
提供一个公有、静态方法获得实例。

 

 

 

下面来看一个这个实现的例子:

 

 

public class SingletonPattern {
 private double r;

 // 定义一个私有、静态的引用变量
 private static SingletonPattern sp;

 // 构造器私有
 private SingletonPattern() {
  r = java.lang.Math.random();
 }

 // 提供一个公有、静态方法获得唯一实例
 public static SingletonPattern getInstance() {
  if (sp == null)// 如果还未创建实例
  {
   sp = new SingletonPattern();// 则创建一个实例
  }
  return sp;// 将它返回
 }

 public double getR() {
  return r;
 }

 public static void main(String args[]) {
  SingletonPattern sp1 = SingletonPattern.getInstance();
  SingletonPattern sp2 = SingletonPattern.getInstance();
  System.out.println(sp1.getR());
  System.out.println(sp2.getR());
 }
}


在这个例子中,我们利用上面所讨论的方法实现了“单子设计模式”,为了简单的测试我们每次得到的对象是否为同一个对象,我们在构造器中给该类的实例变量r赋了一个随机的值。如果每次得到的实例是同一个,那么,它的实例变量r的值也必定相同。

 

为了测试这个类,在这个类中定义了一个main()方法,然后通过SingletonPattern类的静态方法getInstance()来获得两个SingletonPattern实例,分别赋给两个引用变量sp1和sp2,然后通过这两个实例的getR()方法将它的实例变量打印出来。运行上面的程序,可以得到类似如下的输出:
0.04960654267464748
0.04960654267464748


这说明,这两个引用变量指向的是同一个实例,也就是只有一个实例存在。因为这个类的构造器被定义为“private”,所以不能直接调用它的构造器来生成新的实例,这也就避免了通过直接调用构造器生成多个实例的情况。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值