工厂模式和单例模式的使用
在上一篇中简单的说明一下三层架构,为了对数据访问层进一步封装,可以采用工厂模式和单例模式,其中工厂负责生产UserDao的具体实现类,而在一个应用中实现类有一个就够了,所以采用单例模式。
首先,创建配置文件daoconfig.properties,内容如下:
UserDaoImpl=xxx.xxx.UserDaoJdbcImpl
//UserDaoIBatisImpl=xxx.xxx.UserDaoIBatisImpl
创建UserDaoFactory,内容如下:
public class UserDaoFactory
{
private static UserDao userDao = null;
private static UserDaoFactory instance = new UserDaoFactory();
/**
* 构造方法私有
*/
private UserDaoFactory(){
Properties prop = new Properties();
try
{
//加载配置文件
prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
//获得数据访问层的实现类
String userDaoClass = prop.getProperty("UserDaoImpl");
//通过反射获得实现类的一个对像
userDao = Class.forName(userDaoClass).newInstance();
}catch (IOException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
/**
* 返回类的实例
* @return
*/
public UserDaoFactory getInstance(){
return instance;
}
/**
* 返回UserDao的一个实例
* @return
*/
public UserDao getUserDao(){
return userDao;
}
}
上述是工厂模式和单例模式的合集,在应用层,代码如下:
public static void main(String[] args)
{
//数据访问层接口
UserDao userDao = UserDaoFactory.getInstance().getUserDao();
//创建用户
User user = new User(001,"张三","1990-04-25","北京");
//添加用户
userDao.addUser(user);
}
如上所示,此时,我们的业务逻辑层和应用层就是纯粹的面向接口编程,如果数据访问层改变,我们甚至只需要修改配置文件给UserDaoImpl的值修改为新的即可,应用层代码完全不用变。
小插曲:
1. 单例模式的使用方法
(1). 饿汉式
诸如下面代码就是一个简单的饿汉式,在类加载的同时就创建了类的实例,这也是开发中常用的方法。
public class MyClass
{
private static MyClass instance = new MyClass();
private MyClass(){
}
public static MyClass getInstance(){
return Instance;
}
}
(2).懒汉式 下面是懒汉式的写法,它采用延迟加载的方式,但是同时也带来线程不安全的问题。
public class MyClass
{
private static MyClass instance = null;
private MyClass(){
}
public static MyClass getInstance(){
if(instance == null){
instance = new MyClass();
}
return instance;
}
}
当多线程同时访问getInstance()方法时,因为该方法的内部实现不是原子操作,所以线程不安全的,加上关键字synchronized即可。
2. 关于静态加载顺序问题
private static MyClass instance = new MyClass();
private static int x = 0;
private MyClass(){
x = 100;
}
如上所示,当我们访问变量x的时候,它竟然是0,是的没错!在类加载的时候,首先创建instance变量,然后调用构造方法,此时x确实是100,但是往下执行,又把x赋值为0,所以最终x=0。
在上面的工厂模式中如果按下面的顺序定义变量,那就会出错,在执行时出现空指针异常 。
private static UserDaoFactory instance = new UserDaoFactory();
private static UserDao userDao = null;
虽在在UserDaoFactory构造方法中得到了类的实例,但是接下来又赋值为空。
纸上得来终觉浅,觉知此事要躬行。