码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式系列(一)单例模式

时间:2016-08-09 22:04:03      阅读:239      评论:0      收藏:0      [点我收藏+]

标签:

一、用通俗的语言解释其意义:从秦始皇之后确立了皇帝的位置,且同一时期只有一个。因此大家在称呼的时候不需要为皇帝加上其他的前缀。这一过程反应在设计领域就是,要求一个类只能生成一个对象,所有对象对他的依赖都是相同的,因为只有一个对象,所以对象对他的依赖都是相同的,因为只有一个对象,大家对他都很了解。皇帝每天要处理很多的事情,但是皇帝只有一个,即一个类只有一个对象,对象产生通过new关键字完成,我们可以使用构造函数来控制,因为使用new关键字创建对象时都会根据输入的参数调用相应的构造函数,所以如果我们将构造函数的访问权限设置为private就可以进制外部创建对象了。

将以上的情景设置为简单的例子:

皇帝类:

 1 public  class Emperor{
 2 private static final Emperor emperor=new Emperor();//初始化一个皇帝
 3 private Emperor(){
 4 }
 5 public static Emperor getInstance(){
 6 return emperor;
 7 }
 8 public static void say(){
 9 System.out.println("我的就是皇帝");
10 }
11 }

通过定义私有的访问权限的构造函数,避免被其他类new出一个对象,而Emperor自己则可以new一个对象处理,其他类都可以访问getInstance获得同一个对象。

大臣类:

1 public class Minister{
2 public static void main(String[]args){
3 for(int day=0;day<3;day++){
4 Emperor emperor=Emperor.getInstance();
5 emperor.say();
6 }
7 }
8 }


二、单例模式的定义

单例模式(Singleton Pattern):Ensure class has only one instance,and provide a global point of access to it.

Singleton类称为单例类,通过使用private的构造函数确保在一个应用中只产生一个实例。并且是自己实例化的(在Singleton中使用new Singleton)。

单例模式的通用代码:

1 public class Singleton{
2 private static final Singleton singleton=new Singleton();
3 private Singleton(){}
4 public static Singleton getSingleton(){
5 return singleton;
6 }
7 public static void doSomething(){}
8 }

三、单例模式的应用
1、单例模式的优点

  由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的创建和销毁时,而且创建或销毁的性能又无法优化,单例模式的优势就非常明显。

  由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

  单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。

  单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

2、单例模式的缺点

  单例模式一般没有接口,扩展比较困难,若要扩展,除了修改没有第二个办法。单例模式为什么不能增加接口?因为接口对单例模式是没有任何意义的,他要求自行实例化,并且提供单一实例。接口或抽象类是不能被实例化的。

  单例模式对测试是不利的,在单例模式没有完成之前,是不能进行测试的。

  单例模式与单一职责原则是有冲突的,一个类应该只实现一个逻辑,而不关心她是否单例,是不是单例要取决于环境,单例模式将要单例和业务逻辑融合在一个类里。

3、单例模式的使用场景

   要求生成唯一序列号的环境;

   在整个项目中需要一个共享访问点或共享数据,例如一个web页面上的计数器,可以不用把每次刷新都记录到数据库中,使用单例模式爆出加护器的值,并确保线程安全。

   创建一个对象需要消耗资源过多,如要访问IO和数据库等资源

   需要定义大量的静态常量和静态方法如工具类等。

4、单例模式的注意事项

在高并发的情况下,要注意单例模式的线程同步问题

线程不安全的单例:

 1 public class Singleton{
 2 public static Singleton singleton=null;
 3 private Singleton(){}
 4 public static Singleton getSingleton(){
 5 if(singleton==null){
 6 singleton=new Singleton();
 7 }
 8 return singleton;
 9 }
10 }

该单例模式在低并发的情况下是没有问题的,在并发增多时,则可能在内存中存在多个实例,破坏最初的预期。例如线程A执行到singleton=new Singleton()但是没有获得对象,此时第二个线程也开始判断平执行,解决线程不安全的方法很多,可以在getSingleton方法前面加上synchronized来实现;还要考虑对象的复制情况。在java中默认是不可以复制的,若实现的Clonable接口,并实现了clone方法则可以直接通过复制方式创建一个新对象,对象复制是不调用构造函数的,因此即使是私有构造函数依然可以复制。一般很少单例类会主动要求被复制,因此不要实现Clonable接口。
四、单例模式的扩展

我们之前看到的都是单例创建单一对象。如果要多于一个对象该如何。

固定数量的皇帝类:

 1 public class Emperor{
 2 //定义最多能产生的实例实例
 3 private static int maxNumOfEmperor=2;
 4 //每个皇帝都有名字,使用一个ArrayList来容纳,每个对象的私有属性
 5 private static ArrayList<String> nameList=new ArrayList<String>();
 6 //定义一个列表,容纳所有的皇帝实例
 7 private static ArrayList<Emperor> emperorList=new ArrayList<Emperor>();
 8 //当前皇帝序列号
 9 private static int countNumOfEmperor=0;
10 //产生所有的对象
11 static{
12 for(int i=0;i<maxNumOfEmperor;i++){
13 emperorList.add(new Emperor("皇"+i+"帝"));
14 }
15 }
16 private Emperor(){
17 }
18 private Emperor(String name){
19 nameList.add(name);}
20 public static Emperor getInstance(){
21 Random random=new Random();
22 countNumOfEmperor=random.nextInt(maxNumOfEmperor);
23 return emperorList.get(countNumOfEmperor);
24 }
25 public static void say(){
26 System.out.println(nameList.get(countNumOfEmperor));}
27 
28 }

大臣类:

 1 public class Minister{
 2 public static void main(String[]args)
 3 {
 4 int ministerNum=5;
 5 for(int i=0;i<ministerNum;i++){
 6 Emperor emperor=Emperor.getInstance();
 7 System.out.println("第"+(i+1)+"个达成拜的是:");
 8 emperor.say();
 9 }
10 }
11 }


这种也叫作有上限的多例模式。

五、实践

在Spring中。每个Bean默认就是但离得,这样做的有点事Spring容器可以管理他们的生命周期,创建 销毁等。如果才有用非单例模式。则Bean初始化之后的管理交由J2EE容器,Spring容器不再跟踪管理Bean的生命周期。

 

 

 

设计模式系列(一)单例模式

标签:

原文地址:http://www.cnblogs.com/dream-to-pku/p/5754720.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!