java 设计模式--单例模式

单例模式是一种常见的设计模式,在《Java与模式》一书中,阎宏博士对单例模式做了全面的总结。
单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
单例模式有一下特点:
1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
说明:一下的代码来自阎宏博士的《Java与模式》一书,其中对一些类的写法做调整(符合Java1.5的习惯),另外还加了测试方法。

一、懒汉式单例
在类加载的时候不创建单例实例。只有在第一次请求实例的时候的时候创建,并且只在第一次创建后,以后不再创建该类的实例。
public class LazySingleton {
     private static LazySingleton m_intance=null;
     private LazySingleton(){
     }
     synchronized public static LazySingleton getInstance(){
         if(m_intance==null){
             m_intance=new LazySingleton();
         }
         return m_intance;
     }
}
此种要保证为单例,首先要保证构造方法是私有的,然后获取实例的方法一定要是线程安全的,不然不行
问题:如果方法前不加
synchronized  在多线程情况下,两个线程同时调用这个方法,那么此时是报错呢,还是创建了两个实例,个人认为应该是报错吧,因为 m_intance 申明为静态的 ,它能被实例化多次吗

二、饿汉式单例
在类被加载的时候,唯一实例已经被创建。这个设计模式在Java中容易实现,在别的语言中难以实现。
public class EagerSingleton {
     private static final EagerSingleton m_instance = new EagerSingleton();
     private EagerSingleton() {
     }
     public static EagerSingleton getInstance() {
         return m_instance;
     }
}
说明:这里用static final 保证了这个
m_instance 是类变量,而不是属于某个实例的,而且这个引用值是不可变的。这个类在加载时己经创建好了这个实例,所以
不用在方法前在加
synchronized 关键字了 

三、登记式单例
这个单例实际上维护的是一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从工厂直接返回,对于没有登记的,则先登记,而后返回。
public class RegSingleton {
    
     private static Map<String, RegSingleton> m_registry = new HashMap();
     //在类加载的时候添加一个实例到登记薄
     static {
         RegSingleton x = new RegSingleton();
         m_registry.put(x.getClass().getName(), x);
     }
    
     protected RegSingleton() {
     }
    
     public static RegSingleton getInstance(String name) {
         if (name == null) {
             name = "RegSingleton";
         }
         if (m_registry.get(name) == null) {
             try {
                 m_registry.put(name, (RegSingleton) Class.forName(name).newInstance());
             } catch (InstantiationException e) {
                 e.printStackTrace();
             } catch (IllegalAccessException e) {
                 e.printStackTrace();
             } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         }
         return m_registry.get(name);
     }
    
     public String about() {
         return "Hello,I am RegSingleton!";
     }
}

四、单例模式的一个应用
该应用是配置文件管理类。为了本例能正确运行,我在C盘下先建立了一个xxxx.properties文件,内容如下:
-------------------
user=root
password=leizhimin
这个配置文件管理类的代码如下:
public class ConfigManager {
    
     private static final String PFILE = "C:\\xxx.properties";
    
     private File m_file = null;
    
     private long m_lastModifiedTime = 0;
    
     private Properties m_props = null;
    
     private static ConfigManager m_instance = new ConfigManager();
    
     private ConfigManager() {
         m_file = new File(PFILE);
         m_lastModifiedTime = m_file.lastModified();
         if (m_lastModifiedTime == 0) {
             System.err.println(PFILE + " file does not exist!");
         }
         m_props = new Properties();
         try {
             m_props.load(new FileInputStream(PFILE));
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
    
     synchronized public static ConfigManager getInstance() {
         return m_instance;
     }
    
     public final Object getConfigItem(String name, Object defaultVal) {
         long newTime = m_file.lastModified();
         if (newTime == 0) {
             //属性文件不存在
             if (m_lastModifiedTime == 0) {
                 System.err.println(PFILE + " file does not exist!");
             } else {
                 System.err.println(PFILE + " file was deleted!");
             }
             return defaultVal;
         } else if (newTime > m_lastModifiedTime) {
             m_props.clear();
             try {
                 m_props.load(new FileInputStream(PFILE));
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         m_lastModifiedTime = newTime;
         Object val = m_props.getProperty(name);
         if (val == null) {
             return defaultVal;
         } else {
             return val;
         }
     }
}
测试配置文件类:
public class Test_ConfigManager {
     public static void main(String[] args) {
         ConfigManager cfgm = ConfigManager.getInstance();
         Object val1 = cfgm.getConfigItem("sdf", "leizhimin");
         Object val2 = cfgm.getConfigItem("user", "leizhimin");
         System.out.println(val1.toString());
         System.out.println(val2.toString());
     }
}
运行结果:
leizhimin
root
Process finished with exit code 0

五、笔者写的一个JDBC数据库工具类的单例实现
public class DBUtil {
     //单一实例
     private static final DBUtil _instance = new DBUtil();
     //数据源的JNDI
     private static final String datasource = "java:comp/env/jdbc/zvfims";
    
     private DBUtil() {
     }
    
     public DBUtil getInstance() {
         return _instance;
     }
    
     public Connection makeConnection() {
         Connection conn = null;
         try {
             Context ctx = new InitialContext();
             DataSource ds = (DataSource) ctx.lookup(datasource);
             conn = ds.getConnection();
         } catch (NamingException e) {
             System.out.println("获取数据源异常,请AppServer的JNDI数据源配置!");
             e.printStackTrace();
         } catch (SQLException e) {
             System.err.println("获取数据库连接发生异常!");
             e.printStackTrace();
         }
         return conn;
     }
}
通过这个单例类和开放的业务方法,可以为整个系统应用提供数据库连接。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值