您的位置:首页 > 运维架构 > 网站架构

面向接口编程在Java web 三层架构的应用与使用工厂模式解决问题

2010-10-20 19:56 756 查看
面向接口编程在Java web 三层架构的应用与使用工厂模式解决问题
为什么要面向接口编程:
在应用中,我们一般都是面向接口编程的,这样有利于系统的扩展与移植。就像Java Web中的三层架构:展现层、业务逻辑层、数据持久层一样,上层都是调用下层的接口。因为一旦下层实现改变:比如持久层从数据库操作更换为文件操作,上层因为调用下层的接口而不用更改任何代码,利于系统扩展与移植。
面向接口编程的思路要点:
  举一个例子,现在要添加一个用户,数据持久层接口如下所示:
 
package kane;

import java.util.List;
import kane.UserInfo;

/**
* UserInfoDao层接口
* @author kane
*/
public interface UserInfoDao {
//添加注册用户基本信息
public void addUserInfo(UserInfo u);
}


 

 

而其两个实现分别如下:
一、数据库实现代码:
package kane;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import kane.UserInfo;
import kane.DBUtility;

/**
* UserInfoDao接口实现类
* @author kane
*/
public class UserInfoDao4SQL implements UserInfoDao {

public void addUserInfo(UserInfo u) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DBUtility.getConnection();
conn.setAutoCommit(false);
String sql = "insert into user_info(id,username,password) values(?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, u.getId);
pstmt.setString(2, u.getUsername());
pstmt.setString(3, u.getPassword());
pstmt.execute();
conn.commit();
} catch (SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
DBUtility.closePreparedStatement(pstmt);
DBUtility.closeConnection();
}
}
}


 

 

 

 

 
二、文件实现类代码如下:
package kane;

import java.;
import java.util.ArrayList;
import java.util.List;

import kane.UserInfo;

/**
* UserInfoDao接口实现类
* @author kane
*/
public class UserInfoDao4File implements UserInfoDao {
public void addUserInfo(UserInfo u) {
//文件操作实现代码……..
}
}

 

 

这样业务逻辑层代码如下所示:

 

package kane;

import java.sql.Connection;
import java.util.List;

import kane.UserInfoDao;
import kane.UserInfo;

/**
* UserInfoManage业务逻辑
*
* @author kane
*
*/
public class UserInfoManage {
private UserInfoDao userInfoDao = null;

public UserInfoManage () {
userInfoDao = new UserInfoDao4SQL();
}
/**
public UserInfoManage () {
userInfoDao = new UserInfoDao4File();
userInfoDao = (UserInfoDao) InterfaceFactory.getInstance().getBean(
UserInfoDao.class);
}
*/

public void addUserInfo(UserInfo u) {
userInfoDao.addUserInfo(u);
}
}


面向接口编程的问题:

这样如果要使得用户保存从数据库更换为文件,就要修改构造方法中的userInfoDao = new UserInfoDao4SQL();这一行代码,这样就有不符合修改扩展的原则,因为一旦要更改实现,就要更改代码。

面向接口编程问题的解决思路:

具体的做法是将要更改的代码提取到配置文件里,就如同数据库的配置文件,这样就可以直接修改配置文件,而不用修改代码了。这里我们介绍一种方法,叫做工厂模式方法,代码如下:

 
package kane;

import java.util.HashMap;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* 抽取出相同的创建接口对象的方法——采用InterfaceFactory创建各个接口产品
* @author kane 使用单例模式
*/
public class InterfaceFactory {
private static InterfaceFactory instance = null;

private Document document = null;
private Map<String, Object> beanMap = new HashMap<String, Object>();

private InterfaceFactory() {
try {
document = new SAXReader().read(Thread.currentThread()
.getContextClassLoader().getResourceAsStream(
"InterfaceFactory.xml"));
} catch (DocumentException e) {
e.printStackTrace();
}
}

public static InterfaceFactory getInstance() {
if (instance == null) {
instance = new InterfaceFactory();
}
return instance;
}

/**
* 如果Map中有该Bean,则直接返回,否则创建该Bean并将其加入到Map中
* @目的是使得加载效率更高
* @param id
* @return 要取得的Bean
*/
@SuppressWarnings("unchecked")
public synchronized Object getBean(Class c) {
Object bean = null;
bean = beanMap.get(c.getName());
if (bean == null) {
try {
Element e = (Element) document
.selectObject("//interface[@id=/"" + c.getName()
+ "/"]");
String className = e.attributeValue("class");
bean = Class.forName(className).newInstance();
beanMap.put(c.getName(), bean);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e2) {
e2.printStackTrace();
} catch (ClassNotFoundException e3) {
e3.printStackTrace();
}
}
return bean;
}
}

 
配置文件InterfaceFactory.xml代码如下:
 

<?xml version="1.0" encoding="UTF-8"?>
<bean>
<interface id="kane.UserInfoDao" class=" kane.UserInfoDao4SQL" />
</bean>

类InterfaceFactory采用dom4j来解析xml文件,然后在getBean()方法中使用反射机制Class.getName()来生成要采用的接口实现类。并且将实现类放在Map中,这样以后要用到就直接从map中取,提高了效率。配置文件采用了数据库实现,如果要采用文件实现则将配置文件转换为:
<?xml version="1.0" encoding="UTF-8"?>
<bean>
<interface id="kane.UserInfoDao" class=" kane.UserInfoDao4File" />
</bean>

 

这样业务逻辑层的代码修改为如下,这样以后就可以不用修改代码写该配置文件即可完成:

package kane;

import java.sql.Connection;
import java.util.List;

import kane.UserInfoDao;
import kane.UserInfo;
import kane.InterfaceFactory;
/**
* UserInfoManage业务逻辑
*
* @author kane
*
*/
public class UserInfoManage {
private UserInfoDao userInfoDao = null;

public UserInfoManage () {
userInfoDao = (UserInfoDao) InterfaceFactory.getInstance().getBean(
UserInfoDao.class);
}

public void addUserInfo(UserInfo u) {
userInfoDao.addUserInfo(u);
}
}


 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐