参考文献
单例模式VS静态方法 :http://www.cnblogs.com/seesea125/archive/2012/04/05/2433463.html
单例模式解说: http://blog.csdn.net/guolin_blog/article/details/8860649
向原博主致敬!本文的出现主要基于以上两篇博客。为什么说是“单例模式伪应用举例”呢?实际生产环境是不会用实验中方法打印日志与获取数据库连接的,只是单例模式学习用。
场景
阅读完郭霖的单例模式解说,感觉那个小日志工具写的不错,这里自己再写一下,随便把以前学单例模式时写的数据库连接整到一起来复习。
问题来了:为什么使用单例模式而不是静态方法呢?单例模式就比静态方法好吗?
这关乎单例模式存在的意义:你挖空心思整一个单例模式出来,好像很有技巧的样子,可完全没有必要啊?单例能干的事情,静态方法都可以实现。
个人认为单例模式vs静态方法的讨论,实际上 是静态方法 与 非静态方法(实例方法)的讨论。比较赞同以下言论:
“早期的结构化编程,几乎所有的方法都是“静态方法”,引入实例化方法概念是面向对象概念出现以后的事情了,区分静态方法和实例化方法不能单单从性能上去理解,创建c++,java,c#这样面向对象语言的大师引入实例化方法一定不是要解决什么性能、内存的问题,而是为了让开发更加模式化、面向对象化。这样说的话,静态方法和实例化方式的区分是为了解决模式的问题。”
“虽然都能实现目的,但是他们一个是基于对象,一个是面向对象的,就像我们不面相对象也能解决问题一样,面相对象的代码提供一个更好的编程思想。”
也就是说,单例模式更加面向对象。现存的就是合理的,以后遇到这种类型的问题,也可以从应用历史发展的角度考虑,把注意力放到 每种方式实现的优点上来。
实验
单例实现日志工具 与获取数据库连接package design;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* 单例模式
* 定义:用单个的实例去有效地解决一类应用问题
*
* 使用方法:
* 1、定义一个该类的静态成员变量,并指向该类的唯一实例。
* 2、私有化构造方法 3、定义一个静态方法返回该类唯一的实例
*
* 伪应用举例:1、数据库连接 2、生产坏境日志的打印
*
* @date 2016/3/18 10:30
* @author Mr.Snail
*
*/
public class Singleton
{
public static void main(String[] args)
{
LogUtil.getInstance().info("test singleton design modern ");
System.out.println(ConnectionManager.getInstance().getConnection());
}
}
/**
* 单例模式应用 之 日志工具
* 场景分析:为了定位问题方便,每个类中都需要打印。如果每次打印日志(这里以debug级别为例)
* 都 new Log().debug(),也就是记录一次日志 new 一个Log对象,显然浪费内存空间。这种情况就可以
* 使用单例模式来解决。
*
* 说明:生成LogUtil类的单例时 方法二比方法一更优雅,使用方法一只是为了学习一下 传说中的 双重锁定(Double-Check Locking)
* @author Administrator
*
*/
class LogUtil
{
private static int debug = 0;
private static int info = 1;
private static int error = 2;
private static int level = debug;//在配置文件中,值可配置
private LogUtil(){}
private static LogUtil logUtil = null; //方法一
public static LogUtil getInstance()
{
<span style="white-space:pre"> </span>// 双重锁定
if(null == logUtil)
{
synchronized (LogUtil.class)
{
if(null == logUtil)
{
logUtil = new LogUtil();
}
}
}
return logUtil;
}
// private static final LogUtil logUtil = new LogUtil(); 方法二
// public static LogUtil getInstance(){return logUtil}
public void debug(String message)
{
if(debug>=level)
{
System.out.println(message);
}
}
public void info(String message)
{
if(info>=level)
{
System.out.println(message);
}
}
public void error(String message)
{
if(error>=level)
{
System.out.println(message);
}
}
}
/**
* 单例模式应用 之 获取数据库连接
* @author Mr.Snail
*
*/
class ConnectionManager
{
private static final String USERNAME = "root";
private static final String PASSWORD = "1989321_ivy";
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://112.74.21.122:3306/mysql";
//当然一般情况,以上参数都是读取配置文件,或者是依赖注入进来的,这里以读取配件文件为例,随便复习一下
//Properties类的操作方法
Properties properties = new Properties();
private static final ConnectionManager cManager = new ConnectionManager();
private ConnectionManager()
{
// InputStream is = this.getClass().getResourceAsStream("./db.properties");
// try
// {
// properties.load(is);
// USERNAME = properties.getProperty("username");
// PASSWORD = properties.getProperty("password");
// DRIVER = properties.getProperty("driver");
// URL = properties.getProperty("url");
// }
// catch (IOException e)
// {
// LogUtil.getInstance().error(e.toString());
// }
}
public static ConnectionManager getInstance(){return cManager;}
/**
* 获取数据库连接
* @return Connection
*/
public Connection getConnection()
{
Connection conn = null;
try
{
Class.forName(DRIVER);
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
}
catch (ClassNotFoundException e)
{
LogUtil.getInstance().error(e.toString());
throw new RuntimeException(e.toString());
}
catch (SQLException e)
{
LogUtil.getInstance().error(e.toString());
throw new RuntimeException(e.toString());
}
return conn;
}
}