在一个软件系统中,经常有有些特殊的对象就需要一个实例,如果有多个的话,就比较浪费服务器资源,最典型的就是 整个系统的配置文件对象。

普通方式读取配置文件

// 配置文件 SingletonApp.properies

paramA2 = AAAAAA
paramB2 =BBBBBBBBBBB /*************** AppConfig **************************************/ package designPattern_1_Singleton; import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; public class AppConfig {
private String ParamA;
private String ParamB; public String getParamA() {
return ParamA;
} public String getParamB() {
return ParamB;
} public AppConfig()
{
readConfig();
} private void readConfig()
{
Properties prop = new Properties();
InputStream in = null;
try{
in = this.getClass().getResourceAsStream("SingletonApp.properties"); prop.load(in);
this.ParamA = prop.getProperty("paramA2");
this.ParamB = prop.getProperty("paramB2"); }
catch(IOException e){
System.out.println("加载配置文件出错了,详细信息参考以下");
e.printStackTrace();
}
finally{
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}
} } /******************** Client.java *****************************/
package designPattern_1_Singleton; public class Client { public static void main(String[] args) {
// TODO Auto-generated method stub AppConfig app = new AppConfig(); String paramA = app.getParamA();
String paramB = app.getParamB(); System.out.println("paramA = " + paramA + " paramB = " + paramB); } }

不用单例模式实现

上面是不用单例模式实现的功能。那么这段代码有什么问题吗?在实现功能方面来说,是完成了功能,但是设计不够合理,这样做没用一次,就要 new 一个config 类。而且发现所有的 Config 类内容都是一样的。这样的话,就存在浪费资源的,这样就有了优化的方面。

优化的内容就是所有需要用到配置的内容都公用一个 Config 类,这样的话就大大节省了资源。从这个功能的描述我们再抽象一下,就引出了单例模式,下面我们来看一下单例模式的定义:

   单例模式:保证一个类仅有一个实例,并且提供一个它的全局访问点。

这样就要保证在整个系统中保证需要用单例模式的类的构造函数只能执行一次。根据这个思路把上面的例子用单例模式改造一下。

  

 package designPattern_1_Singleton;

 import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; public class SingletonAppConfig { /**
* 定义一个静态变量,来存储创建的类的实例,因为是静态的,所以只能创建一次。
*/
private static SingletonAppConfig instance = new SingletonAppConfig(); /**
* 用来提供外界实例类的函数,因为构造函数私有了,那么返回存放 实例的变量的方式来床创建类。
* @return SingletonAppConfig 的实例
*/
public static SingletonAppConfig getInstance(){
return instance;
} //为了只有一个实例,把构造函数改成私有
private SingletonAppConfig()
{
readConfig();
} private String ParamA;
private String ParamB; public String getParamA() {
return ParamA;
} public String getParamB() {
return ParamB;
} private void readConfig()
{
Properties prop = new Properties();
InputStream in = null;
try{
in = this.getClass().getResourceAsStream("SingletonApp.properties"); prop.load(in);
this.ParamA = prop.getProperty("paramA2");
this.ParamB = prop.getProperty("paramB2"); }
catch(IOException e){
System.out.println("加载配置文件出错了,详细信息参考以下");
e.printStackTrace();
}
finally{
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}
}
} ***************************************************************** package designPattern_1_Singleton; public class Client2 { public static void main(String[] args) {
// TODO Auto-generated method stub
SingletonAppConfig sConfig = SingletonAppConfig.getInstance();
for(int i=0;i<=300;i++)
{
sConfig = SingletonAppConfig.getInstance();
System.out.println(sConfig);
}
System.out.println(sConfig.getParamA()+" **** "+sConfig.getParamB());
}
} **************************************************************
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
designPattern_1_Singleton.SingletonAppConfig@4e8a88a9
AAAAAA **** BBBBBBBBBBB

Singleton_1

  通过以上代理,也实现了读取配置文件的功能,但是明显修改后性能更好,因为修改后,这个类在系统中无论在什么地方调用,都只能实现一个实例,能够节省很多性能,改造后的就是单例模式。

  单例模式整体上有两种实现方式,一种就是上面的这种,饿汉模式,另外一种是懒汉模式。

  那么怎么区分饿汉模式和懒汉模式呢,上面实现的是饿汉模式,下面贴出来懒汉模式,然后在区分下:

 package designPattern_1_Singleton;

 import java.io.IOException;
import java.io.InputStream;
import java.util.Properties; /*
* 懒汉式实现办法
*/
public class Singleton2AppConfig { private static Singleton2AppConfig s2Config = null; public Singleton2AppConfig getInstance(){
//判断是否创建了实例,如果没有则创建
if(s2Config == null){
s2Config = new Singleton2AppConfig();
}
return s2Config;
} private Singleton2AppConfig(){
readConfig();
} private String ParamA;
private String ParamB; public String getParamA() {
return ParamA;
} public String getParamB() {
return ParamB;
} private void readConfig()
{
Properties prop = new Properties();
InputStream in = null;
try{
in = this.getClass().getResourceAsStream("SingletonApp.properties"); prop.load(in);
this.ParamA = prop.getProperty("paramA2");
this.ParamB = prop.getProperty("paramB2"); }
catch(IOException e){
System.out.println("加载配置文件出错了,详细信息参考以下");
e.printStackTrace();
}
finally{
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}
}
}

Singleton_2

  通过 Singleton_1 与 Singleton_2 比较,两个模式的本质区别是:创建对象实例的先后。

   饿汉式单例模式,形象的说就是很饿,要急吼吼的创建实例,急到加载类的时候就创建了实例对象。关键代码是

 /**
* 定义一个静态变量,来存储创建的类的实例,因为是静态的,所以只能创建一次。
*/
private static SingletonAppConfig instance = new SingletonAppConfig();

懒汉式单例模式,很实例的创建拖拖拉拉,能不创建就不创建。直到需要使用的时候再去进行了创建,关键代码是:

 private static Singleton2AppConfig s2Config = null;

 public static Singleton2AppConfig getInstance(){
//判断是否创建了实例,如果没有则创建
if(s2Config == null){
s2Config = new Singleton2AppConfig();
}
return s2Config;
}

通过以上要点总结下单例模式的要点:

   1、因为类的性质,他所有实例都是相同的,因此控制这个类只能有一个实例对象。

   2、定义一个私有静态变量,存放实例后的类,因为是静态变量。

   3、类的改造函数设置为私有,不让外界通过构造函数创建实例对象。

   4、但是使用类总是要实例的,所以就提供一个共有的静态方法来创建实例对象。但是为了让类能够使用这个方法创建对象,所以这个类必须要是静态方法。

        5、通过提供的静态方法(一般都是 getInstance)来创建类实例(因为普通方法需要先实例后才能调用,所以这个方法必须是静态方法)。

  懒汉式和饿汉式模式区别

         1、从时间和空间方面来说,懒汉式是因为用的时候才创建实例,而且在每次创建类的时候都需要判断,所以是时间空间模式。而饿汉式模式是每次装载类的时候就要进行实例,因此是空间换时间。

2、从线程安全方面来讲。饿汉式因为是加载类的时候就实例化了,而虚拟机保证加载类只会加载一次,因此是线程安全的。但是装载类和实例类不同步的懒汉式则是不安全的。

 private static Singleton2AppConfig s2Config = null;

 public static Singleton2AppConfig getInstance(){
//判断是否创建了实例,如果没有则创建
if(s2Config == null){
s2Config = new Singleton2AppConfig();
} return s2Config;
}

这个问题就是要用加锁的方式来解决

 /**
* volatile 修改符保证这个类每次都是执行 volatile
*/
private volatile static Singleton2AppConfig s2Config = null; public static Singleton2AppConfig getInstance(){
//判断是否创建了实例,如果没有则创建
if(s2Config == null){
synchronized (Singleton2AppConfig.class) {
s2Config = new Singleton2AppConfig();
}
} return s2Config;
}

  加锁后由于只是在第一次创建类使用同步锁功能,因此影响也不大。

 实例模式的变种,可能创建指定数量的实例

单例模式的本质是控制类实例化的数量,那么如果单例的这个类如果使用频率高到一个实例不够使用了,那么是否可以达到指定需要的实例数量呢?这个是可以的。实例化有一定的数量后,调用肯定也是有特殊的算法,这里我们不探究调用的算法,只看如果实现指定数量的类实例。看代码:

 package designPattern_1_Singleton;

 import java.util.HashMap;
import java.util.Map; public class Singleton3AppConfig {
private final static String CACHE = "cache"; private static Map<String, Singleton3AppConfig> map = new HashMap<String, Singleton3AppConfig>(); private static int MAX = 3; private static int num = 1; private Singleton3AppConfig() { } public static Singleton3AppConfig getInstance() {
String classkey = CACHE + num;
if (map.get(classkey) == null) { map.put(classkey, new Singleton3AppConfig());
}
num += 1;
if (num > MAX) {
num = 1;
} return map.get(classkey);
}
} /***********************8*************************************/ package designPattern_1_Singleton; public class Client3 { public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<30;i++){
Singleton3AppConfig s3c = Singleton3AppConfig.getInstance();
System.out.println(s3c);
} } } /***********************8*************************************/ designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416
designPattern_1_Singleton.Singleton3AppConfig@5f4fcc96
designPattern_1_Singleton.Singleton3AppConfig@7000bcbc
designPattern_1_Singleton.Singleton3AppConfig@40671416

 这个是单例模式变种,代码很好理解。这儿看执行效果,虽然调用的地方实例了30个,但是从打印内容来看,只有三个 实例化的地址。所以知识实例化了指定的三个实例。(这里补充一点:如果构造函数没有返回一个字符串,那么如果直接输出类的话,就输出的是他的地址

小结

   单例模式是整个设计模式中最好理解,也是在使用场景中最容易分辨使用的设计模式。使用单例模式不会因为使用设计模式让代码变得较复杂。而他的目的就是为了在让合适的类只有一个实例对象,从而达到节省资源开支的目的。

设计模式 — 单例模式(Singleton)的更多相关文章

  1. 设计模式 单例模式(Singleton) [ 转载2 ]

    设计模式 单例模式(Singleton) [ 转载2 ] @author java_my_life 单例模式的结构 单例模式的特点: 单例类只能有一个实例. 单例类必须自己创建自己的唯一实例. 单例类 ...

  2. 设计模式 单例模式(Singleton) [ 转载 ]

    设计模式 单例模式(Singleton) [ 转载 ] 转载请注明出处:http://cantellow.iteye.com/blog/838473 前言 懒汉:调用时才创建对象 饿汉:类初始化时就创 ...

  3. JAVA设计模式-单例模式(Singleton)线程安全与效率

    一,前言 单例模式详细大家都已经非常熟悉了,在文章单例模式的八种写法比较中,对单例模式的概念以及使用场景都做了很不错的说明.请在阅读本文之前,阅读一下这篇文章,因为本文就是按照这篇文章中的八种单例模式 ...

  4. 浅谈设计模式--单例模式(Singleton Pattern)

    题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...

  5. [工作中的设计模式]单例模式singleton

    一.模式解析: 单例模式是最简单和最常用的设计模式,面试的时候,不管新毕业的学生还是已经工作多年的筒子,对单例模式基本都能聊上两句.单例模式主要体现在如下方面: 1.类的构造函数私有化,保证外部不能直 ...

  6. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  7. 设计模式--单例模式Singleton(创建型)

    单例模式很显然是定义一个类,这个类在程序中只有唯一的实例对象.一般单例类的构造函数是私有的,只能通过调用静态函数GetInstance来获取实例. 一.单例模式有三种:懒汉式单例.饿汉式单例.登记式单 ...

  8. 设计模式--单例模式Singleton

    单例模式顾名思义整个程序下只有一个实例,例如一个国家只有一个皇帝,一个军队只有一个将军.单例模式的书写又分为饿汉模式和懒汉模式 饿汉模式   类中代码 package demo; public cla ...

  9. 设计模式——单例模式(Singleton)

    保证一个类仅有一个实例,并提供一个访问它的全局访问点.——DP UML类图 模式说明 个人认为单例模式是所有设计模式中最为简单的一个模式,因为实现这个模式仅需一个类,而不像其他模式需要若干个类.这个模 ...

  10. 设计模式-单例模式(Singleton) (创建型模式)

    //以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Singleton.h #pragma once #include<iostream> class Sin ...

随机推荐

  1. [算法]浅谈求n范围以内的质数(素数)

    汗颜,数学符号表达今天才学会呀-_-# 下面是百度百科对质数的定义 质数(prime number)又称素数,有无限个. 质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数. 求质数的方法 ...

  2. 一本通网站 1378:最短路径(shopth)

    [题目描述] 给出一个有向图G=(V, E),和一个源点v0∈V,请写一个程序输出v0和图G中其它顶点的最短路径.只要所有的有向环权值和都是正的,我们就允许图的边有负值.顶点的标号从1到n(n为图G的 ...

  3. Nginx从入门到实践(三)

    动静分离 动静分离是将网站静态资源(JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问. 动静分离的一种做法是将静态资源部署在nginx上, ...

  4. Ceph rdb

    Ceph 独一无二地用统一的系统提供了对象.块.和文件存储功能,它可靠性高.管理简便.并且是自由软件. Ceph 的强大足以改变公司的 IT 基础架构.和管理海量数据. Ceph 可提供极大的伸缩性— ...

  5. GDB调试技巧:总结篇

    目录 一 写在开头 1.1 本文内容 二 学习资料 三 常用命令 四 调试技巧 注:原创不易,转载请务必注明原作者和出处,感谢支持! 一 写在开头 1.1 本文内容 总结GDB调试的一些常用命令和调试 ...

  6. jemter测试中常见的名词解析

    1.响应时间(RT) 响应时间是指系统对请求做出响应的时间 2.吞吐量(TPS)[Throughput] 吞吐量是指系统在单位时间内处理请求的数量 3.并发用户数 并发用户数是指系统可以同时承载的正常 ...

  7. (Python3 自定义函数实现数字金字塔 代码

    def kzkz(ceng): for i in range(1,ceng+1): print(" "*(ceng-i),end='') n=i while(n>=1): p ...

  8. C语言strcpy,strncpy和strlcpy讲解

    前言 C风格的字符串处理函数有很多,如strcpy().strcat()等等. strcpy与strcat char* strcpy (char* dest, const char* src); ch ...

  9. 关于HashMap put元素的原理

    HashMap集合put元素的原理:(1)计算key的hashCode(2)将key的hashCode作为计算因子,通过哈希算法计算HashMap的数组下标index(3)如果index下标的数组元素 ...

  10. exists,in的区别-mysql

    如说两张表一张是用户表TDefUser(userid,address,phone),一张是消费表TAccConsume(userid,time,amount),我要查消费超过5000的用户记录,那么我 ...